@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.js CHANGED
@@ -166,7 +166,7 @@ var DecoderPlugin = class {
166
166
  };
167
167
 
168
168
  // lib/utils/coordinate_utils.ts
169
- var CoordinateUtils = class {
169
+ var CoordinateUtils = class _CoordinateUtils {
170
170
  /**
171
171
  * Decode a string of coordinates into an object with latitude and longitude in millidegrees
172
172
  * @param stringCoords - The string of coordinates to decode
@@ -183,8 +183,8 @@ var CoordinateUtils = class {
183
183
  longitudeChars = stringCoords.substring(8, 14);
184
184
  }
185
185
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
186
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
187
- results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
186
+ results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * _CoordinateUtils.getDirection(firstChar);
187
+ results.longitude = Number(longitudeChars) / 1e3 * _CoordinateUtils.getDirection(middleChar);
188
188
  } else {
189
189
  return;
190
190
  }
@@ -210,8 +210,8 @@ var CoordinateUtils = class {
210
210
  const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
211
211
  const lonMin = Number(longitudeChars) % 1e3 / 10;
212
212
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
213
- results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
214
- results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
213
+ results.latitude = (latDeg + latMin / 60) * _CoordinateUtils.getDirection(firstChar);
214
+ results.longitude = (lonDeg + lonMin / 60) * _CoordinateUtils.getDirection(middleChar);
215
215
  } else {
216
216
  return;
217
217
  }
@@ -318,6 +318,15 @@ var RouteUtils = class _RouteUtils {
318
318
 
319
319
  // lib/utils/result_formatter.ts
320
320
  var ResultFormatter = class {
321
+ static route(decodeResult, route) {
322
+ decodeResult.raw.route = route;
323
+ decodeResult.formatted.items.push({
324
+ type: "aircraft_route",
325
+ code: "ROUTE",
326
+ label: "Aircraft Route",
327
+ value: RouteUtils.routeToString(route)
328
+ });
329
+ }
321
330
  static state_change(decodeResult, from, to) {
322
331
  decodeResult.raw.state_change = {
323
332
  from,
@@ -354,6 +363,9 @@ var ResultFormatter = class {
354
363
  });
355
364
  }
356
365
  static position(decodeResult, value) {
366
+ if (!value || isNaN(value.latitude) || isNaN(value.longitude)) {
367
+ return;
368
+ }
357
369
  decodeResult.raw.position = value;
358
370
  decodeResult.formatted.items.push({
359
371
  type: "aircraft_position",
@@ -590,17 +602,50 @@ var ResultFormatter = class {
590
602
  value: DateTimeUtils.timestampToString(time, "tod")
591
603
  });
592
604
  }
593
- static text(decodeResult, text2) {
594
- decodeResult.raw.text = text2;
605
+ static day(decodeResult, day) {
606
+ decodeResult.raw.day_of_month = day;
607
+ decodeResult.formatted.items.push({
608
+ type: "day_of_month",
609
+ code: "MSG_DAY",
610
+ label: "Day of Month",
611
+ value: `${day}`
612
+ });
613
+ }
614
+ static departureDay(decodeResult, day) {
615
+ decodeResult.raw.departure_day_of_month = day;
616
+ decodeResult.formatted.items.push({
617
+ type: "day_of_month",
618
+ code: "DEP_DAY",
619
+ label: "Departure Day",
620
+ value: `${day}`
621
+ });
622
+ }
623
+ static arrivalDay(decodeResult, day) {
624
+ decodeResult.raw.arrival_day_of_month = day;
625
+ decodeResult.formatted.items.push({
626
+ type: "day_of_month",
627
+ code: "ARR_DAY",
628
+ label: "Arrival Day",
629
+ value: `${day}`
630
+ });
631
+ }
632
+ static text(decodeResult, text) {
633
+ decodeResult.raw.text = text;
595
634
  decodeResult.formatted.items.push({
596
635
  type: "text",
597
636
  code: "TEXT",
598
637
  label: "Text Message",
599
- value: text2
638
+ value: text
600
639
  });
601
640
  }
602
- static unknown(decodeResult, value) {
603
- decodeResult.remaining.text += "," + value;
641
+ static unknown(decodeResult, value, sep = ",") {
642
+ if (!decodeResult.remaining.text)
643
+ decodeResult.remaining.text = value;
644
+ else
645
+ decodeResult.remaining.text += sep + value;
646
+ }
647
+ static unknownArr(decodeResult, value, sep = ",") {
648
+ this.unknown(decodeResult, value.join(sep), sep);
604
649
  }
605
650
  };
606
651
 
@@ -676,14 +721,14 @@ var Label_5Z_Slash = class extends DecoderPlugin {
676
721
  decodeResult.raw.day_of_month = Number(info[3]);
677
722
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
678
723
  ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
679
- decodeResult.remaining.text = data.slice(3).join("/");
724
+ ResultFormatter.unknownArr(decodeResult, data.slice(3), "/");
680
725
  } else if (type === "B3") {
681
726
  ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
682
727
  ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
683
728
  decodeResult.raw.day_of_month = Number(header[2]);
684
729
  ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
685
730
  if (header.length > 4) {
686
- decodeResult.remaining.text = header.slice(4).join(" ");
731
+ ResultFormatter.unknownArr(decodeResult, header.slice(4), "/");
687
732
  }
688
733
  } else if (type === "C3" && data[1] === "C3 GATE REQ ") {
689
734
  const info = data[2].split(" ");
@@ -691,7 +736,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
691
736
  ResultFormatter.arrivalAirport(decodeResult, info[2]);
692
737
  decodeResult.raw.day_of_month = Number(info[3]);
693
738
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
694
- decodeResult.remaining.text = info.slice(5).join(" ");
739
+ ResultFormatter.unknownArr(decodeResult, info.slice(5), " ");
695
740
  } else if (type === "C3") {
696
741
  ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
697
742
  ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
@@ -703,7 +748,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
703
748
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
704
749
  const estimates = data[3].split(" ");
705
750
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
706
- decodeResult.remaining.text = estimates[2];
751
+ ResultFormatter.unknown(decodeResult, estimates[2]);
707
752
  } else {
708
753
  if (options.debug) {
709
754
  console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
@@ -715,7 +760,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
715
760
  if (options.debug) {
716
761
  console.log(`Decoder: Unknown 5Z message: ${message.text}`);
717
762
  }
718
- decodeResult.remaining.text = message.text;
763
+ ResultFormatter.unknown(decodeResult, message.text);
719
764
  decodeResult.decoded = false;
720
765
  decodeResult.decoder.decodeLevel = "none";
721
766
  }
@@ -743,7 +788,7 @@ var Label_10_LDR = class extends DecoderPlugin {
743
788
  if (options.debug) {
744
789
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
745
790
  }
746
- decodeResult.remaining.text = message.text;
791
+ ResultFormatter.unknown(decodeResult, message.text);
747
792
  decodeResult.decoded = false;
748
793
  decodeResult.decoder.decodeLevel = "none";
749
794
  return decodeResult;
@@ -764,7 +809,7 @@ var Label_10_LDR = class extends DecoderPlugin {
764
809
  if (altRwy != "") {
765
810
  ResultFormatter.alternateRunway(decodeResult, altRwy);
766
811
  }
767
- decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
812
+ ResultFormatter.unknownArr(decodeResult, [...parts.slice(0, 5), ...parts.slice(15)]);
768
813
  decodeResult.decoded = true;
769
814
  decodeResult.decoder.decodeLevel = "partial";
770
815
  return decodeResult;
@@ -791,7 +836,7 @@ var Label_10_POS = class extends DecoderPlugin {
791
836
  if (options.debug) {
792
837
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
793
838
  }
794
- decodeResult.remaining.text = message.text;
839
+ ResultFormatter.unknown(decodeResult, message.text);
795
840
  decodeResult.decoded = false;
796
841
  decodeResult.decoder.decodeLevel = "none";
797
842
  return decodeResult;
@@ -804,7 +849,7 @@ var Label_10_POS = class extends DecoderPlugin {
804
849
  };
805
850
  ResultFormatter.position(decodeResult, position);
806
851
  ResultFormatter.altitude(decodeResult, Number(parts[7]));
807
- decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
852
+ ResultFormatter.unknownArr(decodeResult, [parts[0], ...parts.slice(3, 7), ...parts.slice(8)]);
808
853
  decodeResult.decoded = true;
809
854
  decodeResult.decoder.decodeLevel = "partial";
810
855
  return decodeResult;
@@ -831,7 +876,7 @@ var Label_10_Slash = class extends DecoderPlugin {
831
876
  if (options.debug) {
832
877
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
833
878
  }
834
- decodeResult.remaining.text = message.text;
879
+ ResultFormatter.unknown(decodeResult, message.text);
835
880
  decodeResult.decoded = false;
836
881
  decodeResult.decoder.decodeLevel = "none";
837
882
  return decodeResult;
@@ -858,17 +903,11 @@ var Label_10_Slash = class extends DecoderPlugin {
858
903
  time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
859
904
  timeFormat: "tod"
860
905
  }];
861
- decodeResult.raw.route = { waypoints };
862
- decodeResult.formatted.items.push({
863
- type: "aircraft_route",
864
- code: "ROUTE",
865
- label: "Aircraft Route",
866
- value: RouteUtils.routeToString(decodeResult.raw.route)
867
- });
906
+ ResultFormatter.route(decodeResult, { waypoints });
868
907
  if (parts[16]) {
869
908
  ResultFormatter.departureAirport(decodeResult, parts[16]);
870
909
  }
871
- decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
910
+ ResultFormatter.unknownArr(decodeResult, [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)], "/");
872
911
  decodeResult.decoded = true;
873
912
  decodeResult.decoder.decodeLevel = "partial";
874
913
  return decodeResult;
@@ -890,35 +929,29 @@ var Label_12_N_Space = class extends DecoderPlugin {
890
929
  decodeResult.formatted.description = "Position Report";
891
930
  decodeResult.message = message;
892
931
  const variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*),.(?<airframe>.*),(?<unkwn3>.*)$/;
893
- let results;
894
- if (results = message.text.match(variant1Regex)) {
932
+ let results = message.text.match(variant1Regex);
933
+ if (results?.groups) {
895
934
  if (options.debug) {
896
935
  console.log(`Label 12 N : results`);
897
936
  console.log(results);
898
937
  }
899
- decodeResult.raw.position = {
938
+ ResultFormatter.position(decodeResult, {
900
939
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
901
940
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
902
- };
903
- const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
904
- decodeResult.formatted.items.push({
905
- type: "aircraft_position",
906
- code: "POS",
907
- label: "Aircraft Position",
908
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
909
941
  });
942
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
910
943
  ResultFormatter.altitude(decodeResult, altitude);
911
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
944
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2, results.groups.unkwn3]);
912
945
  decodeResult.decoded = true;
913
946
  decodeResult.decoder.decodeLevel = "partial";
914
- } else {
915
- if (options.debug) {
916
- console.log(`Decoder: Unknown 12 message: ${message.text}`);
917
- }
918
- decodeResult.remaining.text = message.text;
919
- decodeResult.decoded = false;
920
- decodeResult.decoder.decodeLevel = "none";
947
+ return decodeResult;
921
948
  }
949
+ if (options.debug) {
950
+ console.log(`Decoder: Unknown 12 message: ${message.text}`);
951
+ }
952
+ ResultFormatter.unknown(decodeResult, message.text);
953
+ decodeResult.decoded = false;
954
+ decodeResult.decoder.decodeLevel = "none";
922
955
  return decodeResult;
923
956
  }
924
957
  };
@@ -945,12 +978,11 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
945
978
  if (options?.debug) {
946
979
  console.log(`Decoder: Unknown OOOI message: ${message.text}`);
947
980
  }
948
- decodeResult.remaining.text = message.text;
981
+ ResultFormatter.unknown(decodeResult, message.text);
949
982
  decodeResult.decoded = false;
950
983
  decodeResult.decoder.decodeLevel = "none";
951
984
  return decodeResult;
952
985
  }
953
- decodeResult.remaining.text = "";
954
986
  const data = parts[2].split(" ");
955
987
  ResultFormatter.departureAirport(decodeResult, data[1]);
956
988
  ResultFormatter.arrivalAirport(decodeResult, data[2]);
@@ -966,7 +998,7 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
966
998
  ResultFormatter.in(decodeResult, time);
967
999
  }
968
1000
  if (parts.length === 7) {
969
- decodeResult.remaining.text += parts.slice(4).join("/");
1001
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), "/");
970
1002
  }
971
1003
  for (let i = 1; i < lines.length; i++) {
972
1004
  if (lines[i].startsWith("/LOC")) {
@@ -980,11 +1012,9 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
980
1012
  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)))
981
1013
  };
982
1014
  }
983
- if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
984
- ResultFormatter.position(decodeResult, position);
985
- }
1015
+ ResultFormatter.position(decodeResult, position);
986
1016
  } else {
987
- decodeResult.remaining.text += "\r\n" + lines[i];
1017
+ ResultFormatter.unknown(decodeResult, lines[i], "\r\n");
988
1018
  }
989
1019
  }
990
1020
  decodeResult.decoded = true;
@@ -1029,16 +1059,8 @@ var Label_15 = class extends DecoderPlugin {
1029
1059
  decodeResult.formatted.description = "Position Report";
1030
1060
  const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
1031
1061
  const results = message.text.match(twoZeeRegex);
1032
- if (results) {
1033
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13));
1034
- if (decodeResult.raw.position) {
1035
- decodeResult.formatted.items.push({
1036
- type: "position",
1037
- code: "POS",
1038
- label: "Position",
1039
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1040
- });
1041
- }
1062
+ if (results?.groups) {
1063
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13)));
1042
1064
  }
1043
1065
  decodeResult.decoded = true;
1044
1066
  decodeResult.decoder.decodeLevel = "partial";
@@ -1062,31 +1084,23 @@ var Label_15_FST = class extends DecoderPlugin {
1062
1084
  decodeResult.message = message;
1063
1085
  const parts = message.text.split(" ");
1064
1086
  const header = parts[0];
1065
- decodeResult.raw.departure_icao = header.substring(5, 9);
1066
- decodeResult.raw.arrival_icao = header.substring(9, 13);
1067
1087
  const stringCoords = header.substring(13);
1068
1088
  const firstChar = stringCoords.substring(0, 1);
1069
1089
  const middleChar = stringCoords.substring(7, 8);
1070
1090
  decodeResult.raw.position = {};
1071
1091
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
1072
- decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
1073
- decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
1074
- decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
1092
+ const lat = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
1093
+ const lon = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
1094
+ ResultFormatter.position(decodeResult, { latitude: lat, longitude: lon });
1095
+ ResultFormatter.altitude(decodeResult, Number(stringCoords.substring(15)) * 100);
1075
1096
  } else {
1076
1097
  decodeResult.decoded = false;
1077
1098
  decodeResult.decoder.decodeLevel = "none";
1078
1099
  return decodeResult;
1079
1100
  }
1080
- decodeResult.formatted.items.push({
1081
- type: "aircraft_position",
1082
- code: "POS",
1083
- label: "Aircraft Position",
1084
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1085
- });
1086
- ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
1087
- ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
1088
- ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
1089
- decodeResult.remaining.text = parts.slice(1).join(" ");
1101
+ ResultFormatter.departureAirport(decodeResult, header.substring(5, 9));
1102
+ ResultFormatter.arrivalAirport(decodeResult, header.substring(9, 13));
1103
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), " ");
1090
1104
  decodeResult.decoded = true;
1091
1105
  decodeResult.decoder.decodeLevel = "partial";
1092
1106
  return decodeResult;
@@ -1109,52 +1123,45 @@ var Label_16_N_Space = class extends DecoderPlugin {
1109
1123
  decodeResult.message = message;
1110
1124
  let variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*)$/;
1111
1125
  let variant2Regex = /^(?<lat>[NS])\s(?<lat_coord>.*)\/(?<long>[EW])\s*(?<long_coord>.*)$/;
1112
- let results;
1113
- if (results = message.text.match(variant1Regex)) {
1126
+ let results = message.text.match(variant1Regex);
1127
+ if (results?.groups) {
1114
1128
  if (options.debug) {
1115
1129
  console.log(`Label 16 N : results`);
1116
1130
  console.log(results);
1117
1131
  }
1118
- decodeResult.raw.position = {
1132
+ let pos = {
1119
1133
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
1120
1134
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
1121
1135
  };
1122
1136
  const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
1123
- decodeResult.formatted.items.push({
1124
- type: "aircraft_position",
1125
- code: "POS",
1126
- label: "Aircraft Position",
1127
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1128
- });
1137
+ ResultFormatter.position(decodeResult, pos);
1129
1138
  ResultFormatter.altitude(decodeResult, altitude);
1130
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
1139
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2]);
1131
1140
  decodeResult.decoded = true;
1132
1141
  decodeResult.decoder.decodeLevel = "partial";
1133
- } else if (results = message.text.match(variant2Regex)) {
1142
+ return decodeResult;
1143
+ }
1144
+ results = message.text.match(variant2Regex);
1145
+ if (results?.groups) {
1134
1146
  if (options.debug) {
1135
1147
  console.log(`Label 16 N : results`);
1136
1148
  console.log(results);
1137
1149
  }
1138
- decodeResult.raw.position = {
1150
+ let pos = {
1139
1151
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
1140
1152
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
1141
1153
  };
1142
- decodeResult.formatted.items.push({
1143
- type: "aircraft_position",
1144
- code: "POS",
1145
- label: "Aircraft Position",
1146
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1147
- });
1154
+ ResultFormatter.position(decodeResult, pos);
1148
1155
  decodeResult.decoded = true;
1149
1156
  decodeResult.decoder.decodeLevel = "full";
1150
- } else {
1151
- if (options.debug) {
1152
- console.log(`Decoder: Unknown 16 message: ${message.text}`);
1153
- }
1154
- decodeResult.remaining.text = message.text;
1155
- decodeResult.decoded = false;
1156
- decodeResult.decoder.decodeLevel = "none";
1157
+ return decodeResult;
1158
+ }
1159
+ if (options.debug) {
1160
+ console.log(`Decoder: Unknown 16 message: ${message.text}`);
1157
1161
  }
1162
+ ResultFormatter.unknown(decodeResult, message.text);
1163
+ decodeResult.decoded = false;
1164
+ decodeResult.decoder.decodeLevel = "none";
1158
1165
  return decodeResult;
1159
1166
  }
1160
1167
  };
@@ -1193,6 +1200,265 @@ var Label_1M_Slash = class extends DecoderPlugin {
1193
1200
  }
1194
1201
  };
1195
1202
 
1203
+ // lib/plugins/Label_1L_3-line.ts
1204
+ var Label_1L_3Line = class extends DecoderPlugin {
1205
+ // eslint-disable-line camelcase
1206
+ name = "label-1l-3-line";
1207
+ qualifiers() {
1208
+ return {
1209
+ labels: ["1L"]
1210
+ };
1211
+ }
1212
+ decode(message, options = {}) {
1213
+ const decodeResult = this.defaultResult();
1214
+ decodeResult.decoder.name = this.name;
1215
+ decodeResult.formatted.description = "Position Report";
1216
+ decodeResult.message = message;
1217
+ const lines = message.text.split("\r\n");
1218
+ if (lines.length !== 3) {
1219
+ if (options.debug) {
1220
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1221
+ }
1222
+ decodeResult.remaining.text = message.text;
1223
+ decodeResult.decoded = false;
1224
+ decodeResult.decoder.decodeLevel = "none";
1225
+ return decodeResult;
1226
+ }
1227
+ const parts = message.text.replaceAll("\r\n", "/").split("/");
1228
+ const data = /* @__PURE__ */ new Map();
1229
+ data.set("", parts[0]);
1230
+ for (let i = 1; i < parts.length; i++) {
1231
+ const part = parts[i].split(" ");
1232
+ data.set(part[0], part.slice(1).join(" "));
1233
+ }
1234
+ const dep = data.get("DEP");
1235
+ if (dep) {
1236
+ ResultFormatter.departureAirport(decodeResult, dep);
1237
+ data.delete("DEP");
1238
+ }
1239
+ const des = data.get("DES");
1240
+ if (des) {
1241
+ ResultFormatter.arrivalAirport(decodeResult, des);
1242
+ data.delete("DES");
1243
+ }
1244
+ const eta = data.get("ETA");
1245
+ if (eta) {
1246
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1247
+ data.delete("ETA");
1248
+ }
1249
+ const alt = data.get("ALT");
1250
+ if (alt) {
1251
+ ResultFormatter.altitude(decodeResult, Number(alt));
1252
+ data.delete("ALT");
1253
+ }
1254
+ const fn = data.get("FN");
1255
+ if (fn) {
1256
+ ResultFormatter.flightNumber(decodeResult, fn);
1257
+ data.delete("FN");
1258
+ }
1259
+ const day = data.get("DAY");
1260
+ const utc = data.get("UTC");
1261
+ if (day && utc) {
1262
+ decodeResult.raw.message_timestamp = Date.parse(day + " GMT+0000") / 1e3 + DateTimeUtils.convertHHMMSSToTod(utc);
1263
+ data.delete("DAY");
1264
+ data.delete("UTC");
1265
+ }
1266
+ const lat = data.get("LAT");
1267
+ const lon = data.get("LON");
1268
+ if (lat && lon) {
1269
+ ResultFormatter.position(decodeResult, {
1270
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
1271
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
1272
+ });
1273
+ data.delete("LAT");
1274
+ data.delete("LON");
1275
+ }
1276
+ let remaining = "";
1277
+ for (const [key, value] of data.entries()) {
1278
+ if (key === "") {
1279
+ remaining += value;
1280
+ } else {
1281
+ remaining += `/${key} ${value}`;
1282
+ }
1283
+ }
1284
+ decodeResult.remaining.text = remaining;
1285
+ decodeResult.decoded = true;
1286
+ decodeResult.decoder.decodeLevel = "partial";
1287
+ return decodeResult;
1288
+ }
1289
+ };
1290
+
1291
+ // lib/plugins/Label_1L_070.ts
1292
+ var Label_1L_070 = class extends DecoderPlugin {
1293
+ // eslint-disable-line camelcase
1294
+ name = "label-1l-070";
1295
+ qualifiers() {
1296
+ return {
1297
+ labels: ["1L"],
1298
+ preambles: ["000000070"]
1299
+ };
1300
+ }
1301
+ decode(message, options = {}) {
1302
+ const decodeResult = this.defaultResult();
1303
+ decodeResult.decoder.name = this.name;
1304
+ decodeResult.formatted.description = "Position Report";
1305
+ decodeResult.message = message;
1306
+ if (!message.text.startsWith("000000070")) {
1307
+ if (options.debug) {
1308
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1309
+ }
1310
+ decodeResult.remaining.text = message.text;
1311
+ decodeResult.decoded = false;
1312
+ decodeResult.decoder.decodeLevel = "none";
1313
+ return decodeResult;
1314
+ }
1315
+ const parts = message.text.substring(9).split(",");
1316
+ if (parts.length !== 7) {
1317
+ if (options.debug) {
1318
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1319
+ }
1320
+ decodeResult.remaining.text = message.text;
1321
+ decodeResult.decoded = false;
1322
+ decodeResult.decoder.decodeLevel = "none";
1323
+ return decodeResult;
1324
+ }
1325
+ ResultFormatter.departureAirport(decodeResult, parts[0]);
1326
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
1327
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2] + "00"));
1328
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3] + "00"));
1329
+ ResultFormatter.position(decodeResult, {
1330
+ latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
1331
+ longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
1332
+ });
1333
+ decodeResult.remaining.text = parts[6];
1334
+ decodeResult.decoded = true;
1335
+ decodeResult.decoder.decodeLevel = "partial";
1336
+ return decodeResult;
1337
+ }
1338
+ };
1339
+
1340
+ // lib/plugins/Label_1L_660.ts
1341
+ var Label_1L_660 = class extends DecoderPlugin {
1342
+ // eslint-disable-line camelcase
1343
+ name = "label-1l-660";
1344
+ qualifiers() {
1345
+ return {
1346
+ labels: ["1L"],
1347
+ preambles: ["000000660"]
1348
+ };
1349
+ }
1350
+ decode(message, options = {}) {
1351
+ const decodeResult = this.defaultResult();
1352
+ decodeResult.decoder.name = this.name;
1353
+ decodeResult.formatted.description = "Position Report";
1354
+ decodeResult.message = message;
1355
+ if (!message.text.startsWith("000000660")) {
1356
+ if (options.debug) {
1357
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1358
+ }
1359
+ decodeResult.remaining.text = message.text;
1360
+ decodeResult.decoded = false;
1361
+ decodeResult.decoder.decodeLevel = "none";
1362
+ return decodeResult;
1363
+ }
1364
+ const parts = message.text.substring(9).split(",");
1365
+ if (parts.length !== 5) {
1366
+ if (options.debug) {
1367
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1368
+ }
1369
+ decodeResult.remaining.text = message.text;
1370
+ decodeResult.decoded = false;
1371
+ decodeResult.decoder.decodeLevel = "none";
1372
+ return decodeResult;
1373
+ }
1374
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(parts[0]);
1375
+ if (position) {
1376
+ ResultFormatter.position(decodeResult, position);
1377
+ }
1378
+ const hhmmss = parts[1].substring(0, 6);
1379
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(hhmmss));
1380
+ const fl = parts[1].substring(6, 9);
1381
+ ResultFormatter.altitude(decodeResult, Number(fl) * 100);
1382
+ const next = parts[1].substring(9);
1383
+ ResultFormatter.route(decodeResult, { waypoints: [{ name: next.trim() }] });
1384
+ decodeResult.remaining.text = parts.slice(2).join(",");
1385
+ decodeResult.decoded = true;
1386
+ decodeResult.decoder.decodeLevel = "partial";
1387
+ return decodeResult;
1388
+ }
1389
+ };
1390
+
1391
+ // lib/plugins/Label_1L_Slash.ts
1392
+ var Label_1L_Slash = class extends DecoderPlugin {
1393
+ // eslint-disable-line camelcase
1394
+ name = "label-1l-1-line";
1395
+ qualifiers() {
1396
+ return {
1397
+ labels: ["1L"],
1398
+ preambles: ["+", "-"]
1399
+ };
1400
+ }
1401
+ decode(message, options = {}) {
1402
+ const decodeResult = this.defaultResult();
1403
+ decodeResult.decoder.name = this.name;
1404
+ decodeResult.formatted.description = "Position Report";
1405
+ decodeResult.message = message;
1406
+ const parts = message.text.split("/");
1407
+ if (parts.length !== 7) {
1408
+ if (options.debug) {
1409
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1410
+ }
1411
+ decodeResult.remaining.text = message.text;
1412
+ decodeResult.decoded = false;
1413
+ decodeResult.decoder.decodeLevel = "none";
1414
+ return decodeResult;
1415
+ }
1416
+ const data = /* @__PURE__ */ new Map();
1417
+ data.set("LAT", parts[0].replaceAll(" ", ""));
1418
+ data.set("LON", parts[1].replaceAll(" ", ""));
1419
+ for (let i = 2; i < parts.length; i++) {
1420
+ const part = parts[i].split(" ");
1421
+ data.set(part[0], part.slice(1).join(" "));
1422
+ }
1423
+ console.log(data);
1424
+ const position = {
1425
+ latitude: Number(data.get("LAT")),
1426
+ longitude: Number(data.get("LON"))
1427
+ };
1428
+ data.delete("LAT");
1429
+ data.delete("LON");
1430
+ ResultFormatter.position(decodeResult, position);
1431
+ const utc = data.get("UTC");
1432
+ if (utc) {
1433
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(utc));
1434
+ data.delete("UTC");
1435
+ }
1436
+ const alt = data.get("ALT");
1437
+ if (alt) {
1438
+ ResultFormatter.altitude(decodeResult, Number(alt));
1439
+ data.delete("ALT");
1440
+ }
1441
+ const fob = data.get("FOB");
1442
+ if (fob) {
1443
+ ResultFormatter.currentFuel(decodeResult, Number(fob));
1444
+ data.delete("FOB");
1445
+ }
1446
+ const eta = data.get("ETA");
1447
+ if (eta) {
1448
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1449
+ data.delete("ETA");
1450
+ }
1451
+ let remaining = "";
1452
+ for (const [key, value] of data.entries()) {
1453
+ remaining += `/${key} ${value}`;
1454
+ }
1455
+ decodeResult.remaining.text = remaining;
1456
+ decodeResult.decoded = true;
1457
+ decodeResult.decoder.decodeLevel = "partial";
1458
+ return decodeResult;
1459
+ }
1460
+ };
1461
+
1196
1462
  // lib/plugins/Label_20_POS.ts
1197
1463
  var Label_20_POS = class extends DecoderPlugin {
1198
1464
  name = "label-20-pos";
@@ -1215,30 +1481,16 @@ var Label_20_POS = class extends DecoderPlugin {
1215
1481
  console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1216
1482
  }
1217
1483
  const rawCoords = fields[0];
1218
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1219
- if (decodeResult.raw.position) {
1220
- decodeResult.formatted.items.push({
1221
- type: "position",
1222
- code: "POS",
1223
- label: "Position",
1224
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1225
- });
1226
- }
1484
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(rawCoords));
1227
1485
  decodeResult.decoded = true;
1228
1486
  decodeResult.decoder.decodeLevel = "full";
1229
1487
  } else if (fields.length == 5) {
1230
1488
  if (options.debug) {
1231
1489
  console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1232
1490
  }
1233
- const rawCoords = fields[0];
1234
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1235
- if (decodeResult.raw.position) {
1236
- decodeResult.formatted.items.push({
1237
- type: "position",
1238
- code: "POS",
1239
- label: "Position",
1240
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1241
- });
1491
+ const position = CoordinateUtils.decodeStringCoordinates(fields[0]);
1492
+ if (position) {
1493
+ ResultFormatter.position(decodeResult, position);
1242
1494
  }
1243
1495
  decodeResult.decoded = true;
1244
1496
  decodeResult.decoder.decodeLevel = "full";
@@ -1277,11 +1529,7 @@ var Label_21_POS = class extends DecoderPlugin {
1277
1529
  ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
1278
1530
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
1279
1531
  ResultFormatter.arrivalAirport(decodeResult, fields[8]);
1280
- decodeResult.remaining.text = [
1281
- fields[1],
1282
- fields[4],
1283
- fields[5]
1284
- ].join(",");
1532
+ ResultFormatter.unknownArr(decodeResult, [fields[1], fields[4], fields[5]]);
1285
1533
  decodeResult.decoded = true;
1286
1534
  decodeResult.decoder.decodeLevel = "partial";
1287
1535
  } else {
@@ -1307,41 +1555,74 @@ function processPosition(decodeResult, value) {
1307
1555
  ResultFormatter.position(decodeResult, position);
1308
1556
  }
1309
1557
 
1310
- // lib/plugins/Label_24_Slash.ts
1311
- var Label_24_Slash = class extends DecoderPlugin {
1312
- name = "label-24-slash";
1558
+ // lib/plugins/Label_22_OFF.ts
1559
+ var Label_22_OFF = class extends DecoderPlugin {
1560
+ name = "label-22-off";
1313
1561
  qualifiers() {
1314
1562
  return {
1315
- labels: ["24"],
1316
- preambles: ["/"]
1563
+ labels: ["22"],
1564
+ preambles: ["OFF"]
1317
1565
  };
1318
1566
  }
1319
1567
  decode(message, options = {}) {
1320
1568
  const decodeResult = this.defaultResult();
1321
1569
  decodeResult.decoder.name = this.name;
1322
- decodeResult.formatted.description = "Position Report";
1570
+ decodeResult.formatted.description = "Takeoff Report";
1323
1571
  decodeResult.message = message;
1324
- const fields = message.text.split("/");
1325
- if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1326
- const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1327
- const hhmmss = fields[2] + "00";
1328
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1329
- ResultFormatter.flightNumber(decodeResult, fields[3]);
1330
- ResultFormatter.altitude(decodeResult, Number(fields[4]));
1331
- const lat = fields[5];
1332
- const lon = fields[6];
1333
- const position = {
1334
- latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1335
- longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1336
- };
1337
- ResultFormatter.position(decodeResult, position);
1338
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1339
- decodeResult.remaining.text = fields[7];
1572
+ if (message.text.startsWith("OFF01")) {
1573
+ const fields = message.text.substring(5).split("/");
1574
+ if (fields.length != 2) {
1575
+ decodeResult.decoded = false;
1576
+ decodeResult.decoder.decodeLevel = "none";
1577
+ return decodeResult;
1578
+ }
1579
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1580
+ ResultFormatter.departureDay(decodeResult, Number(fields[1].substring(0, 2)));
1581
+ ResultFormatter.arrivalDay(decodeResult, Number(fields[1].substring(2, 4)));
1582
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8) + "00"));
1583
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(8, 12));
1584
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
1585
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22)));
1586
+ ResultFormatter.unknown(decodeResult, fields[1].substring(22));
1587
+ decodeResult.decoded = true;
1588
+ decodeResult.decoder.decodeLevel = "partial";
1589
+ } else if (message.text.startsWith("OFF02\r\n")) {
1590
+ const fields = message.text.substring(7).split(",");
1591
+ if (fields.length != 4) {
1592
+ decodeResult.decoded = false;
1593
+ decodeResult.decoder.decodeLevel = "none";
1594
+ return decodeResult;
1595
+ }
1596
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
1597
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
1598
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1599
+ ResultFormatter.unknown(decodeResult, fields[3]);
1600
+ decodeResult.decoded = true;
1601
+ decodeResult.decoder.decodeLevel = "partial";
1602
+ } else if (message.text.startsWith("OFF02")) {
1603
+ const fields = message.text.substring(5).split("/");
1604
+ if (fields.length != 2) {
1605
+ decodeResult.decoded = false;
1606
+ decodeResult.decoder.decodeLevel = "none";
1607
+ return decodeResult;
1608
+ }
1609
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1610
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(fields[1].substring(0, 14));
1611
+ if (position) {
1612
+ ResultFormatter.position(decodeResult, position);
1613
+ }
1614
+ ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
1615
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20) + "00"));
1616
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(20, 24));
1617
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
1618
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32) + "00"));
1619
+ ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
1620
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40) + "00"));
1340
1621
  decodeResult.decoded = true;
1341
1622
  decodeResult.decoder.decodeLevel = "partial";
1342
1623
  } else {
1343
1624
  if (options.debug) {
1344
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1625
+ console.log(`DEBUG: ${this.name}: Unknown variation.`);
1345
1626
  }
1346
1627
  decodeResult.decoded = false;
1347
1628
  decodeResult.decoder.decodeLevel = "none";
@@ -1350,33 +1631,116 @@ var Label_24_Slash = class extends DecoderPlugin {
1350
1631
  }
1351
1632
  };
1352
1633
 
1353
- // lib/plugins/Label_30_Slash_EA.ts
1354
- var Label_30_Slash_EA = class extends DecoderPlugin {
1355
- name = "label-30-slash-ea";
1634
+ // lib/plugins/Label_22_POS.ts
1635
+ var Label_22_POS = class extends DecoderPlugin {
1636
+ name = "label-22-pos";
1356
1637
  qualifiers() {
1357
1638
  return {
1358
- labels: ["30"],
1359
- preambles: ["/EA"]
1639
+ labels: ["22"],
1640
+ preambles: ["N", "S"]
1360
1641
  };
1361
1642
  }
1362
1643
  decode(message, options = {}) {
1363
1644
  const decodeResult = this.defaultResult();
1364
1645
  decodeResult.decoder.name = this.name;
1365
- decodeResult.formatted.description = "ETA Report";
1646
+ decodeResult.formatted.description = "Position Report";
1366
1647
  decodeResult.message = message;
1367
- const results = message.text.split(/\n|\//).slice(1);
1368
- if (results) {
1648
+ const fields = message.text.split(",");
1649
+ if (fields.length !== 11) {
1369
1650
  if (options.debug) {
1370
- console.log(`Label 30 EA: results`);
1371
- console.log(results);
1651
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${fields.join(",")}`);
1652
+ }
1653
+ decodeResult.decoded = false;
1654
+ decodeResult.decoder.decodeLevel = "none";
1655
+ return decodeResult;
1656
+ }
1657
+ const latStr = fields[0].substring(1, 8);
1658
+ const lonStr = fields[0].substring(9);
1659
+ const lat = Number(latStr) / 1e4;
1660
+ const lon = Number(lonStr) / 1e4;
1661
+ ResultFormatter.position(decodeResult, {
1662
+ latitude: CoordinateUtils.getDirection(fields[0][0]) * lat,
1663
+ longitude: CoordinateUtils.getDirection(fields[0][8]) * lon
1664
+ });
1665
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1666
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1667
+ ResultFormatter.unknownArr(decodeResult, [fields[1], ...fields.slice(4)]);
1668
+ decodeResult.decoded = true;
1669
+ decodeResult.decoder.decodeLevel = "partial";
1670
+ return decodeResult;
1671
+ }
1672
+ };
1673
+
1674
+ // lib/plugins/Label_24_Slash.ts
1675
+ var Label_24_Slash = class extends DecoderPlugin {
1676
+ name = "label-24-slash";
1677
+ qualifiers() {
1678
+ return {
1679
+ labels: ["24"],
1680
+ preambles: ["/"]
1681
+ };
1682
+ }
1683
+ decode(message, options = {}) {
1684
+ const decodeResult = this.defaultResult();
1685
+ decodeResult.decoder.name = this.name;
1686
+ decodeResult.formatted.description = "Position Report";
1687
+ decodeResult.message = message;
1688
+ const fields = message.text.split("/");
1689
+ if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1690
+ const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1691
+ const hhmmss = fields[2] + "00";
1692
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1693
+ ResultFormatter.flightNumber(decodeResult, fields[3]);
1694
+ ResultFormatter.altitude(decodeResult, Number(fields[4]));
1695
+ const lat = fields[5];
1696
+ const lon = fields[6];
1697
+ const position = {
1698
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1699
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1700
+ };
1701
+ ResultFormatter.position(decodeResult, position);
1702
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1703
+ ResultFormatter.unknown(decodeResult, fields[7]);
1704
+ decodeResult.decoded = true;
1705
+ decodeResult.decoder.decodeLevel = "partial";
1706
+ } else {
1707
+ if (options.debug) {
1708
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1709
+ }
1710
+ decodeResult.decoded = false;
1711
+ decodeResult.decoder.decodeLevel = "none";
1712
+ }
1713
+ return decodeResult;
1714
+ }
1715
+ };
1716
+
1717
+ // lib/plugins/Label_30_Slash_EA.ts
1718
+ var Label_30_Slash_EA = class extends DecoderPlugin {
1719
+ name = "label-30-slash-ea";
1720
+ qualifiers() {
1721
+ return {
1722
+ labels: ["30"],
1723
+ preambles: ["/EA"]
1724
+ };
1725
+ }
1726
+ decode(message, options = {}) {
1727
+ const decodeResult = this.defaultResult();
1728
+ decodeResult.decoder.name = this.name;
1729
+ decodeResult.formatted.description = "ETA Report";
1730
+ decodeResult.message = message;
1731
+ const results = message.text.split(/\n|\//).slice(1);
1732
+ if (results) {
1733
+ if (options.debug) {
1734
+ console.log(`Label 30 EA: results`);
1735
+ console.log(results);
1372
1736
  }
1373
1737
  }
1374
1738
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1375
1739
  if (results[1].substring(0, 2) === "DS") {
1376
1740
  ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1377
- decodeResult.remaining.text = "/".concat(results[2]);
1741
+ ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
1378
1742
  } else {
1379
- decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
1743
+ ResultFormatter.unknown(decodeResult, "/".concat(results[1], "/", results[2]));
1380
1744
  }
1381
1745
  decodeResult.decoded = true;
1382
1746
  decodeResult.decoder.decodeLevel = "partial";
@@ -1400,40 +1764,20 @@ var Label_44_ETA = class extends DecoderPlugin {
1400
1764
  decodeResult.message = message;
1401
1765
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1402
1766
  const results = message.text.match(regex);
1403
- if (results) {
1767
+ if (results?.groups) {
1404
1768
  if (options.debug) {
1405
1769
  console.log(`Label 44 ETA Report: groups`);
1406
1770
  console.log(results.groups);
1407
1771
  }
1408
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1409
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1410
- 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);
1411
1775
  decodeResult.raw.current_time = Date.parse(
1412
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"
1413
1777
  );
1414
1778
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1415
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1416
- }
1417
- if (decodeResult.raw.position) {
1418
- decodeResult.formatted.items.push({
1419
- type: "position",
1420
- code: "POS",
1421
- label: "Position",
1422
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1423
- });
1779
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1424
1780
  }
1425
- decodeResult.formatted.items.push({
1426
- type: "origin",
1427
- code: "ORG",
1428
- label: "Origin",
1429
- value: decodeResult.raw.departure_icao
1430
- });
1431
- decodeResult.formatted.items.push({
1432
- type: "destination",
1433
- code: "DST",
1434
- label: "Destination",
1435
- value: decodeResult.raw.arrival_icao
1436
- });
1437
1781
  }
1438
1782
  decodeResult.decoded = true;
1439
1783
  decodeResult.decoder.decodeLevel = "full";
@@ -1457,40 +1801,20 @@ var Label_44_IN = class extends DecoderPlugin {
1457
1801
  decodeResult.message = message;
1458
1802
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1459
1803
  const results = message.text.match(regex);
1460
- if (results) {
1804
+ if (results?.groups) {
1461
1805
  if (options.debug) {
1462
1806
  console.log(`Label 44 In Air Report: groups`);
1463
1807
  console.log(results.groups);
1464
1808
  }
1465
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1466
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1467
- 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);
1468
1812
  decodeResult.raw.current_time = Date.parse(
1469
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"
1470
1814
  );
1471
1815
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1472
1816
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1473
1817
  }
1474
- if (decodeResult.raw.position) {
1475
- decodeResult.formatted.items.push({
1476
- type: "position",
1477
- code: "POS",
1478
- label: "Position",
1479
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1480
- });
1481
- }
1482
- decodeResult.formatted.items.push({
1483
- type: "origin",
1484
- code: "ORG",
1485
- label: "Origin",
1486
- value: decodeResult.raw.departure_icao
1487
- });
1488
- decodeResult.formatted.items.push({
1489
- type: "destination",
1490
- code: "DST",
1491
- label: "Destination",
1492
- value: decodeResult.raw.arrival_icao
1493
- });
1494
1818
  }
1495
1819
  decodeResult.decoded = true;
1496
1820
  decodeResult.decoder.decodeLevel = "full";
@@ -1514,13 +1838,14 @@ var Label_44_OFF = class extends DecoderPlugin {
1514
1838
  decodeResult.message = message;
1515
1839
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1516
1840
  const results = message.text.match(regex);
1517
- if (results) {
1841
+ if (results?.groups) {
1518
1842
  if (options.debug) {
1519
1843
  console.log(`Label 44 Off Runway Report: groups`);
1520
1844
  console.log(results.groups);
1521
1845
  }
1522
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1523
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1846
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1847
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1848
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1524
1849
  decodeResult.raw.current_time = Date.parse(
1525
1850
  (/* @__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"
1526
1851
  );
@@ -1530,27 +1855,6 @@ var Label_44_OFF = class extends DecoderPlugin {
1530
1855
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1531
1856
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1532
1857
  }
1533
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1534
- if (decodeResult.raw.position) {
1535
- decodeResult.formatted.items.push({
1536
- type: "position",
1537
- code: "POS",
1538
- label: "Position",
1539
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1540
- });
1541
- }
1542
- decodeResult.formatted.items.push({
1543
- type: "origin",
1544
- code: "ORG",
1545
- label: "Origin",
1546
- value: decodeResult.raw.departure_icao
1547
- });
1548
- decodeResult.formatted.items.push({
1549
- type: "destination",
1550
- code: "DST",
1551
- label: "Destination",
1552
- value: decodeResult.raw.arrival_icao
1553
- });
1554
1858
  }
1555
1859
  decodeResult.decoded = true;
1556
1860
  decodeResult.decoder.decodeLevel = "full";
@@ -1574,40 +1878,20 @@ var Label_44_ON = class extends DecoderPlugin {
1574
1878
  decodeResult.message = message;
1575
1879
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1576
1880
  const results = message.text.match(regex);
1577
- if (results) {
1881
+ if (results?.groups) {
1578
1882
  if (options.debug) {
1579
1883
  console.log(`Label 44 On Runway Report: groups`);
1580
1884
  console.log(results.groups);
1581
1885
  }
1582
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1583
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1584
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1886
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1887
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1888
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1585
1889
  decodeResult.raw.current_time = Date.parse(
1586
1890
  (/* @__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"
1587
1891
  );
1588
1892
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1589
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1893
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1590
1894
  }
1591
- if (decodeResult.raw.position) {
1592
- decodeResult.formatted.items.push({
1593
- type: "position",
1594
- code: "POS",
1595
- label: "Position",
1596
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1597
- });
1598
- }
1599
- decodeResult.formatted.items.push({
1600
- type: "origin",
1601
- code: "ORG",
1602
- label: "Origin",
1603
- value: decodeResult.raw.departure_icao
1604
- });
1605
- decodeResult.formatted.items.push({
1606
- type: "destination",
1607
- code: "DST",
1608
- label: "Destination",
1609
- value: decodeResult.raw.arrival_icao
1610
- });
1611
1895
  }
1612
1896
  decodeResult.decoded = true;
1613
1897
  decodeResult.decoder.decodeLevel = "full";
@@ -1631,12 +1915,12 @@ var Label_44_POS = class extends DecoderPlugin {
1631
1915
  decodeResult.message = message;
1632
1916
  const regex = /^.*,(?<unsplit_coords>.*),(?<flight_level_or_ground>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1633
1917
  const results = message.text.match(regex);
1634
- if (results) {
1918
+ if (results?.groups) {
1635
1919
  if (options.debug) {
1636
1920
  console.log(`Label 44 Position Report: groups`);
1637
1921
  console.log(results.groups);
1638
1922
  }
1639
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
1923
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords));
1640
1924
  const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
1641
1925
  decodeResult.raw.current_time = Date.parse(
1642
1926
  (/* @__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"
@@ -1647,14 +1931,6 @@ var Label_44_POS = class extends DecoderPlugin {
1647
1931
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1648
1932
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1649
1933
  }
1650
- if (decodeResult.raw.position) {
1651
- decodeResult.formatted.items.push({
1652
- type: "aircraft_position",
1653
- code: "POS",
1654
- label: "Aircraft Position",
1655
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1656
- });
1657
- }
1658
1934
  ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1659
1935
  ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1660
1936
  ResultFormatter.altitude(decodeResult, flight_level * 100);
@@ -1678,13 +1954,13 @@ var Label_4A = class extends DecoderPlugin {
1678
1954
  decodeResult.decoder.name = this.name;
1679
1955
  decodeResult.message = message;
1680
1956
  decodeResult.formatted.description = "Latest New Format";
1681
- let text2 = message.text;
1682
- if (text2.match(/^M\d{2}A\w{6}/)) {
1957
+ let text = message.text;
1958
+ if (text.match(/^M\d{2}A\w{6}/)) {
1683
1959
  ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1684
- text2 = text2.substring(10);
1960
+ text = text.substring(10);
1685
1961
  }
1686
1962
  decodeResult.decoded = true;
1687
- const fields = text2.split(",");
1963
+ const fields = text.split(",");
1688
1964
  if (fields.length === 11) {
1689
1965
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1690
1966
  ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
@@ -1692,8 +1968,8 @@ var Label_4A = class extends DecoderPlugin {
1692
1968
  ResultFormatter.callsign(decodeResult, fields[3]);
1693
1969
  ResultFormatter.departureAirport(decodeResult, fields[4]);
1694
1970
  ResultFormatter.arrivalAirport(decodeResult, fields[5]);
1695
- ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
1696
- decodeResult.remaining.text = fields.slice(8).join(",");
1971
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
1972
+ ResultFormatter.unknownArr(decodeResult, fields.slice(8));
1697
1973
  } else if (fields.length === 6) {
1698
1974
  if (fields[0].match(/^[NS]/)) {
1699
1975
  ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
@@ -1702,31 +1978,25 @@ var Label_4A = class extends DecoderPlugin {
1702
1978
  time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
1703
1979
  timeFormat: "tod"
1704
1980
  };
1705
- ResultFormatter.altitude(decodeResult, fields[1].substring(6, 9) * 100);
1981
+ ResultFormatter.altitude(decodeResult, Number(fields[1].substring(6, 9)) * 100);
1706
1982
  let wp2 = {
1707
1983
  name: fields[1].substring(9).trim(),
1708
1984
  time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
1709
1985
  timeFormat: "tod"
1710
1986
  };
1711
- decodeResult.raw.route = { waypoints: [wp1, wp2] };
1712
- decodeResult.formatted.items.push({
1713
- type: "aircraft_route",
1714
- code: "ROUTE",
1715
- label: "Aircraft Route",
1716
- value: RouteUtils.routeToString(decodeResult.raw.route)
1717
- });
1987
+ ResultFormatter.route(decodeResult, { waypoints: [wp1, wp2] });
1718
1988
  ResultFormatter.temperature(decodeResult, fields[3]);
1719
- decodeResult.remaining.text = fields.slice(4).join(",");
1989
+ ResultFormatter.unknownArr(decodeResult, fields.slice(4));
1720
1990
  } else {
1721
1991
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1722
1992
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
1723
- decodeResult.remaining.text = fields[2];
1724
- ResultFormatter.altitude(decodeResult, fields[3]);
1993
+ ResultFormatter.unknown(decodeResult, fields[2]);
1994
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1725
1995
  ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
1726
1996
  }
1727
1997
  } else {
1728
1998
  decodeResult.decoded = false;
1729
- decodeResult.remaining.text = text2;
1999
+ ResultFormatter.unknown(decodeResult, text);
1730
2000
  }
1731
2001
  if (decodeResult.decoded) {
1732
2002
  if (!decodeResult.remaining.text)
@@ -1763,11 +2033,11 @@ var Label_4A_01 = class extends DecoderPlugin {
1763
2033
  ResultFormatter.departureAirport(decodeResult, rgx[5]);
1764
2034
  ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
1765
2035
  ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
1766
- decodeResult.remaining.text = rgx[8];
2036
+ ResultFormatter.unknown(decodeResult, rgx[8]);
1767
2037
  ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
1768
2038
  } else {
1769
2039
  decodeResult.decoded = false;
1770
- decodeResult.remaining.text = message.text;
2040
+ ResultFormatter.unknown(decodeResult, message.text);
1771
2041
  }
1772
2042
  if (decodeResult.decoded) {
1773
2043
  if (!decodeResult.remaining.text)
@@ -1833,7 +2103,7 @@ var Label_4A_DOOR = class extends DecoderPlugin {
1833
2103
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1834
2104
  } else {
1835
2105
  decodeResult.decoded = false;
1836
- decodeResult.remaining.text = text;
2106
+ ResultFormatter.unknown(decodeResult, message.text);
1837
2107
  }
1838
2108
  if (decodeResult.decoded) {
1839
2109
  if (!decodeResult.remaining.text)
@@ -1863,10 +2133,10 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
1863
2133
  decodeResult.formatted.description = "Latest New Format";
1864
2134
  decodeResult.decoded = true;
1865
2135
  if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
1866
- decodeResult.remaining.text = message.text.substring(4);
2136
+ ResultFormatter.unknown(decodeResult, message.text.substring(4));
1867
2137
  } else {
1868
2138
  decodeResult.decoded = false;
1869
- decodeResult.remaining.text = message.text;
2139
+ ResultFormatter.unknown(decodeResult, message.text);
1870
2140
  }
1871
2141
  if (decodeResult.decoded) {
1872
2142
  if (!decodeResult.remaining.text)
@@ -1880,630 +2150,93 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
1880
2150
  }
1881
2151
  };
1882
2152
 
1883
- // lib/plugins/Label_4N.ts
1884
- var Label_4N = class extends DecoderPlugin {
1885
- name = "label-4n";
1886
- qualifiers() {
1887
- return {
1888
- labels: ["4N"]
1889
- };
1890
- }
1891
- decode(message, options = {}) {
1892
- const decodeResult = this.defaultResult();
1893
- decodeResult.decoder.name = this.name;
1894
- decodeResult.message = message;
1895
- decodeResult.formatted.description = "Airline Defined";
1896
- let text2 = message.text;
1897
- if (text2.match(/^M\d{2}A\w{6}/)) {
1898
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1899
- text2 = text2.substring(10);
1900
- }
1901
- decodeResult.decoded = true;
1902
- const fields = text2.split(",");
1903
- if (text2.length === 51) {
1904
- decodeResult.raw.day_of_month = text2.substring(0, 2);
1905
- ResultFormatter.departureAirport(decodeResult, text2.substring(8, 11));
1906
- ResultFormatter.arrivalAirport(decodeResult, text2.substring(13, 16));
1907
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(30, 45).replace(/^(.)0/, "$1")));
1908
- ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
1909
- decodeResult.remaining.text = [text2.substring(2, 4), text2.substring(19, 29)].join(" ");
1910
- } else if (fields.length === 33) {
1911
- decodeResult.raw.date = fields[3];
1912
- if (fields[1] === "B") {
1913
- ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
1914
- ResultFormatter.altitude(decodeResult, fields[6]);
2153
+ // lib/utils/flight_plan_utils.ts
2154
+ var FlightPlanUtils = class _FlightPlanUtils {
2155
+ /**
2156
+ * Processes flight plan data
2157
+ *
2158
+ * Expected format is [header, key1, val1, ... keyN, valN]
2159
+ *
2160
+ * @param decodeResult - results
2161
+ * @param data - original message split by ':'
2162
+ * @returns whether all fields were processed or not
2163
+ */
2164
+ static processFlightPlan(decodeResult, data) {
2165
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2166
+ for (let i = 1; i < data.length; i += 2) {
2167
+ const key = data[i];
2168
+ const value = data[i + 1];
2169
+ switch (key) {
2170
+ case "A":
2171
+ addProcedure(decodeResult, value, "arrival");
2172
+ break;
2173
+ case "AA":
2174
+ addArrivalAirport(decodeResult, value);
2175
+ break;
2176
+ case "AP":
2177
+ addProcedure(decodeResult, value, "approach");
2178
+ break;
2179
+ case "CR":
2180
+ addCompanyRoute(decodeResult, value);
2181
+ break;
2182
+ case "D":
2183
+ addProcedure(decodeResult, value, "departure");
2184
+ break;
2185
+ case "DA":
2186
+ addDepartureAirport(decodeResult, value);
2187
+ break;
2188
+ case "F":
2189
+ addRoute(decodeResult, value);
2190
+ break;
2191
+ case "R":
2192
+ addRunway(decodeResult, value);
2193
+ break;
2194
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
2195
+ // break;
2196
+ default:
2197
+ if (allKnownFields) {
2198
+ decodeResult.remaining.text = "";
2199
+ allKnownFields = false;
2200
+ }
2201
+ decodeResult.remaining.text += `:${key}:${value}`;
2202
+ decodeResult.decoder.decodeLevel = "partial";
1915
2203
  }
1916
- ResultFormatter.departureAirport(decodeResult, fields[8]);
1917
- ResultFormatter.arrivalAirport(decodeResult, fields[9]);
1918
- ResultFormatter.alternateAirport(decodeResult, fields[10]);
1919
- ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
1920
- if (fields[12].length > 1) {
1921
- ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2204
+ }
2205
+ return allKnownFields;
2206
+ }
2207
+ static parseHeader(decodeResult, header) {
2208
+ let allKnownFields = true;
2209
+ if (header.startsWith("RF")) {
2210
+ decodeResult.formatted.items.push({
2211
+ type: "status",
2212
+ code: "ROUTE_STATUS",
2213
+ label: "Route Status",
2214
+ value: "Route Filed"
2215
+ });
2216
+ decodeResult.raw.route_status = "RF";
2217
+ if (header.length > 2) {
2218
+ addRoute(decodeResult, header.substring(2));
1922
2219
  }
1923
- ResultFormatter.checksum(decodeResult, fields[32]);
1924
- decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
2220
+ } else if (header.startsWith("RP")) {
2221
+ decodeResult.raw.route_status = "RP";
2222
+ decodeResult.formatted.items.push({
2223
+ type: "status",
2224
+ code: "ROUTE_STATUS",
2225
+ label: "Route Status",
2226
+ value: "Route Planned"
2227
+ });
2228
+ decodeResult.raw.route_status = header;
2229
+ } else if (header.startsWith("RI")) {
2230
+ decodeResult.raw.route_status = "RI";
2231
+ decodeResult.formatted.items.push({
2232
+ type: "status",
2233
+ code: "ROUTE_STATUS",
2234
+ label: "Route Status",
2235
+ value: "Route Inactive"
2236
+ });
1925
2237
  } else {
1926
- decodeResult.decoded = false;
1927
- decodeResult.remaining.text = text2;
1928
- }
1929
- if (decodeResult.decoded) {
1930
- if (!decodeResult.remaining.text)
1931
- decodeResult.decoder.decodeLevel = "full";
1932
- else
1933
- decodeResult.decoder.decodeLevel = "partial";
1934
- } else {
1935
- decodeResult.decoder.decodeLevel = "none";
1936
- }
1937
- return decodeResult;
1938
- }
1939
- };
1940
-
1941
- // lib/plugins/Label_80.ts
1942
- var Label_80 = class extends DecoderPlugin {
1943
- name = "label-80";
1944
- descriptions = {
1945
- ALT: "Altitude",
1946
- DWND: "Wind Direction",
1947
- ETA: "Estimated Time of Arrival",
1948
- FOB: "Fuel on Board",
1949
- FL: "Flight Level",
1950
- HDG: "Heading",
1951
- MCH: "Aircraft Speed",
1952
- NWYP: "Next Waypoint",
1953
- POS: "Aircraft Position",
1954
- SAT: "Static Air Temperature",
1955
- SWND: "Wind Speed",
1956
- TAS: "True Airspeed",
1957
- WYP: "Waypoint"
1958
- };
1959
- qualifiers() {
1960
- return {
1961
- labels: ["80"],
1962
- preambles: ["3N01 POSRPT"]
1963
- };
1964
- }
1965
- decode(message, options = {}) {
1966
- const decodeResult = this.defaultResult();
1967
- decodeResult.decoder.name = this.name;
1968
- decodeResult.formatted.description = "Airline Defined Position Report";
1969
- const parts = message.text.split("\n");
1970
- let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
1971
- let results = parts[0].match(posRptRegex);
1972
- if (!results?.groups) {
1973
- decodeResult.decoded = false;
1974
- decodeResult.decoder.decodeLevel = "none";
1975
- return decodeResult;
1976
- }
1977
- if (results && results.length > 0) {
1978
- ResultFormatter.departureAirport(decodeResult, results.groups.orig);
1979
- ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
1980
- ResultFormatter.tail(decodeResult, results.groups.tail);
1981
- if (results.groups.agate) {
1982
- decodeResult.raw.arrival_gate = results.groups.agate;
1983
- decodeResult.formatted.items.push({
1984
- type: "arrival_gate",
1985
- code: "ARG",
1986
- label: "Arrival Gate",
1987
- value: `${results.groups.agate}`
1988
- });
1989
- decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
1990
- decodeResult.formatted.items.push({
1991
- type: "scheduled_time_of_arrival",
1992
- code: "STA",
1993
- label: "Scheduled Time of Arrival",
1994
- value: `${results.groups.sta}`
1995
- });
1996
- }
1997
- posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
1998
- const remainingParts = parts.slice(1);
1999
- for (const part of remainingParts) {
2000
- const matches = part.matchAll(posRptRegex);
2001
- for (const match of matches) {
2002
- switch (match.groups?.field) {
2003
- case "ALT": {
2004
- ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2005
- break;
2006
- }
2007
- case "DWND": {
2008
- decodeResult.raw.wind_direction = Number(match.groups.value);
2009
- decodeResult.formatted.items.push({
2010
- type: "wind_direction",
2011
- code: "DWND",
2012
- label: this.descriptions[match.groups.field],
2013
- value: decodeResult.raw.wind_direction
2014
- });
2015
- break;
2016
- }
2017
- case "FL": {
2018
- const flight_level = Number(match.groups.value);
2019
- ResultFormatter.altitude(decodeResult, flight_level * 100);
2020
- break;
2021
- }
2022
- case "FOB": {
2023
- decodeResult.raw.fuel_on_board = match.groups.value;
2024
- decodeResult.formatted.items.push({
2025
- type: "fuel_on_board",
2026
- code: "FOB",
2027
- label: this.descriptions[match.groups.field],
2028
- value: decodeResult.raw.fuel_on_board
2029
- });
2030
- break;
2031
- }
2032
- case "HDG": {
2033
- decodeResult.raw.heading = Number(match.groups.value);
2034
- decodeResult.formatted.items.push({
2035
- type: "heading",
2036
- code: "HDG",
2037
- label: this.descriptions[match.groups.field],
2038
- value: decodeResult.raw.heading
2039
- });
2040
- break;
2041
- }
2042
- case "MCH": {
2043
- decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2044
- decodeResult.formatted.items.push({
2045
- type: "mach",
2046
- code: "MCH",
2047
- label: this.descriptions[match.groups.field],
2048
- value: `${decodeResult.raw.mach} Mach`
2049
- });
2050
- break;
2051
- }
2052
- case "NWYP": {
2053
- decodeResult.raw.next_waypoint = match.groups.value;
2054
- decodeResult.formatted.items.push({
2055
- type: "next_waypoint",
2056
- code: "NWYP",
2057
- label: this.descriptions[match.groups.field],
2058
- value: decodeResult.raw.next_waypoint
2059
- });
2060
- break;
2061
- }
2062
- case "POS": {
2063
- const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2064
- const posResult = match.groups.value.match(posRegex);
2065
- const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2066
- const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2067
- const position = {
2068
- latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2069
- longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2070
- };
2071
- ResultFormatter.position(decodeResult, position);
2072
- break;
2073
- }
2074
- case "SWND": {
2075
- decodeResult.raw.wind_speed = Number(match.groups.value);
2076
- decodeResult.formatted.items.push({
2077
- type: "wind_speed",
2078
- code: "SWND",
2079
- label: this.descriptions[match.groups.field],
2080
- value: decodeResult.raw.wind_speed
2081
- });
2082
- break;
2083
- }
2084
- default: {
2085
- if (match.groups?.field != void 0) {
2086
- const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2087
- decodeResult.formatted.items.push({
2088
- type: match.groups.field,
2089
- code: match.groups.field,
2090
- label: description || `Unknown (${match.groups.field})`,
2091
- value: `${match.groups.value}`
2092
- });
2093
- }
2094
- }
2095
- }
2096
- }
2097
- }
2098
- decodeResult.decoded = true;
2099
- decodeResult.decoder.decodeLevel = "partial";
2100
- }
2101
- return decodeResult;
2102
- }
2103
- };
2104
-
2105
- // lib/plugins/Label_83.ts
2106
- var Label_83 = class extends DecoderPlugin {
2107
- name = "label-83";
2108
- qualifiers() {
2109
- return {
2110
- labels: ["83"]
2111
- };
2112
- }
2113
- decode(message, options = {}) {
2114
- const decodeResult = this.defaultResult();
2115
- decodeResult.decoder.name = this.name;
2116
- decodeResult.message = message;
2117
- decodeResult.formatted.description = "Airline Defined";
2118
- let text2 = message.text;
2119
- if (text2.match(/^M\d{2}A\w{6}/)) {
2120
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2121
- text2 = text2.substring(10);
2122
- }
2123
- decodeResult.decoded = true;
2124
- if (text2.substring(0, 10) === "4DH3 ETAT2") {
2125
- const fields = text2.split(/\s+/);
2126
- if (fields[2].length > 5) {
2127
- decodeResult.raw.day_of_month = fields[2].substring(5);
2128
- }
2129
- decodeResult.remaining.text = fields[2].substring(0, 4);
2130
- const subfields = fields[3].split("/");
2131
- ResultFormatter.departureAirport(decodeResult, subfields[0]);
2132
- ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2133
- ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2134
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2135
- } else if (text2.substring(0, 5) === "001PR") {
2136
- decodeResult.raw.day_of_month = text2.substring(5, 7);
2137
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(13, 28).replace(/\./g, ""));
2138
- if (position) {
2139
- ResultFormatter.position(decodeResult, position);
2140
- }
2141
- ResultFormatter.altitude(decodeResult, Number(text2.substring(28, 33)));
2142
- decodeResult.remaining.text = text2.substring(33);
2143
- } else {
2144
- const fields = text2.replace(/\s/g, "").split(",");
2145
- if (fields.length === 9) {
2146
- ResultFormatter.departureAirport(decodeResult, fields[0]);
2147
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2148
- decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2149
- decodeResult.raw.time = fields[2].substring(2);
2150
- ResultFormatter.position(
2151
- decodeResult,
2152
- {
2153
- latitude: Number(fields[3].replace(/\s/g, "")),
2154
- longitude: Number(fields[4].replace(/\s/g, ""))
2155
- }
2156
- );
2157
- ResultFormatter.altitude(decodeResult, Number(fields[5]));
2158
- ResultFormatter.groundspeed(decodeResult, fields[6]);
2159
- ResultFormatter.heading(decodeResult, fields[7]);
2160
- decodeResult.remaining.text = fields[8];
2161
- } else {
2162
- decodeResult.decoded = false;
2163
- decodeResult.remaining.text = message.text;
2164
- }
2165
- }
2166
- if (decodeResult.decoded) {
2167
- if (!decodeResult.remaining.text)
2168
- decodeResult.decoder.decodeLevel = "full";
2169
- else
2170
- decodeResult.decoder.decodeLevel = "partial";
2171
- } else {
2172
- decodeResult.decoder.decodeLevel = "none";
2173
- }
2174
- return decodeResult;
2175
- }
2176
- };
2177
-
2178
- // lib/plugins/Label_8E.ts
2179
- var Label_8E = class extends DecoderPlugin {
2180
- name = "label-8e";
2181
- qualifiers() {
2182
- return {
2183
- labels: ["8E"]
2184
- };
2185
- }
2186
- decode(message, options = {}) {
2187
- const decodeResult = this.defaultResult();
2188
- decodeResult.decoder.name = this.name;
2189
- decodeResult.formatted.description = "ETA Report";
2190
- decodeResult.message = message;
2191
- const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2192
- const results = message.text.match(regex);
2193
- if (results) {
2194
- if (options.debug) {
2195
- console.log(`Label 8E ETA: groups`);
2196
- console.log(results.groups);
2197
- }
2198
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2199
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2200
- }
2201
- decodeResult.decoded = true;
2202
- decodeResult.decoder.decodeLevel = "full";
2203
- return decodeResult;
2204
- }
2205
- };
2206
-
2207
- // lib/plugins/Label_B6.ts
2208
- var Label_B6_Forwardslash = class extends DecoderPlugin {
2209
- name = "label-b6-forwardslash";
2210
- qualifiers() {
2211
- return {
2212
- labels: ["B6"],
2213
- preambles: ["/"]
2214
- };
2215
- }
2216
- decode(message, options = {}) {
2217
- const decodeResult = this.defaultResult();
2218
- decodeResult.decoder.name = this.name;
2219
- decodeResult.formatted.description = "CPDLC Message";
2220
- decodeResult.message = message;
2221
- if (options.debug) {
2222
- console.log("CPDLC: " + message);
2223
- }
2224
- return decodeResult;
2225
- }
2226
- };
2227
-
2228
- // lib/plugins/Label_ColonComma.ts
2229
- var Label_ColonComma = class extends DecoderPlugin {
2230
- name = "label-colon-comma";
2231
- qualifiers() {
2232
- return {
2233
- labels: [":;"]
2234
- };
2235
- }
2236
- decode(message, options = {}) {
2237
- const decodeResult = this.defaultResult();
2238
- decodeResult.decoder.name = this.name;
2239
- decodeResult.raw.frequency = Number(message.text) / 1e3;
2240
- decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2241
- decodeResult.formatted.items.push({
2242
- type: "frequency",
2243
- label: "Frequency",
2244
- value: `${decodeResult.raw.frequency} MHz`
2245
- });
2246
- decodeResult.decoded = true;
2247
- decodeResult.decoder.decodeLevel = "full";
2248
- return decodeResult;
2249
- }
2250
- };
2251
-
2252
- // lib/plugins/Label_H1_FLR.ts
2253
- var Label_H1_FLR = class extends DecoderPlugin {
2254
- name = "label-h1-flr";
2255
- qualifiers() {
2256
- return {
2257
- labels: ["H1"],
2258
- preambles: ["FLR", "#CFBFLR"]
2259
- };
2260
- }
2261
- decode(message, options = {}) {
2262
- let decodeResult = this.defaultResult();
2263
- decodeResult.decoder.name = this.name;
2264
- decodeResult.formatted.description = "Fault Log Report";
2265
- decodeResult.message = message;
2266
- const parts = message.text.split("/FR");
2267
- if (parts.length > 1) {
2268
- decodeResult.remaining.text = "";
2269
- const fields = parts[0].split("/");
2270
- for (let i = 1; i < fields.length; i++) {
2271
- const field = fields[i];
2272
- if (field.startsWith("PN")) {
2273
- processUnknown(decodeResult, "/" + field);
2274
- } else {
2275
- processUnknown(decodeResult, "/" + field);
2276
- }
2277
- }
2278
- const data = parts[1].substring(0, 20);
2279
- const msg = parts[1].substring(20);
2280
- const datetime = data.substring(0, 12);
2281
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2282
- processUnknown(decodeResult, data.substring(12));
2283
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2284
- decodeResult.raw.fault_message = msg;
2285
- decodeResult.formatted.items.push({
2286
- type: "fault",
2287
- code: "FR",
2288
- label: "Fault Report",
2289
- value: decodeResult.raw.fault_message
2290
- });
2291
- decodeResult.decoded = true;
2292
- decodeResult.decoder.decodeLevel = "partial";
2293
- } else {
2294
- if (options.debug) {
2295
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2296
- }
2297
- decodeResult.remaining.text = message.text;
2298
- decodeResult.decoded = false;
2299
- decodeResult.decoder.decodeLevel = "none";
2300
- }
2301
- return decodeResult;
2302
- }
2303
- };
2304
- function processUnknown(decodeResult, value) {
2305
- decodeResult.remaining.text += value;
2306
- }
2307
-
2308
- // lib/plugins/Label_H1_OHMA.ts
2309
- var zlib = __toESM(require("minizlib"));
2310
- var Label_H1_OHMA = class extends DecoderPlugin {
2311
- name = "label-h1-ohma";
2312
- qualifiers() {
2313
- return {
2314
- labels: ["H1"],
2315
- preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
2316
- };
2317
- }
2318
- decode(message, options = {}) {
2319
- let decodeResult = this.defaultResult();
2320
- decodeResult.decoder.name = this.name;
2321
- decodeResult.formatted.description = "OHMA Message";
2322
- decodeResult.message = message;
2323
- decodeResult.remaining.text = "";
2324
- const data = message.text.split("OHMA")[1];
2325
- try {
2326
- const compressedBuffer = Buffer.from(data, "base64");
2327
- const decompress = new zlib.Inflate({ windowBits: 15 });
2328
- decompress.write(compressedBuffer);
2329
- decompress.flush(zlib.constants.Z_SYNC_FLUSH);
2330
- const result = decompress.read();
2331
- const jsonText = result.toString();
2332
- let formattedMsg;
2333
- let jsonMessage;
2334
- try {
2335
- jsonMessage = JSON.parse(jsonText).message;
2336
- } catch {
2337
- jsonMessage = jsonText;
2338
- }
2339
- try {
2340
- const ohmaMsg = JSON.parse(jsonMessage);
2341
- formattedMsg = JSON.stringify(ohmaMsg, null, 2);
2342
- } catch {
2343
- formattedMsg = jsonMessage;
2344
- }
2345
- decodeResult.decoded = true;
2346
- decodeResult.decoder.decodeLevel = "full";
2347
- decodeResult.raw.ohma = jsonText;
2348
- decodeResult.formatted.items.push({
2349
- type: "ohma",
2350
- code: "OHMA",
2351
- label: "OHMA Downlink",
2352
- value: formattedMsg
2353
- });
2354
- } catch (e) {
2355
- if (options.debug) {
2356
- console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
2357
- }
2358
- decodeResult.remaining.text += message.text;
2359
- decodeResult.decoded = false;
2360
- decodeResult.decoder.decodeLevel = "none";
2361
- }
2362
- return decodeResult;
2363
- }
2364
- };
2365
-
2366
- // lib/plugins/Label_H1_WRN.ts
2367
- var Label_H1_WRN = class extends DecoderPlugin {
2368
- name = "label-h1-wrn";
2369
- qualifiers() {
2370
- return {
2371
- labels: ["H1"],
2372
- preambles: ["WRN", "#CFBWRN"]
2373
- };
2374
- }
2375
- decode(message, options = {}) {
2376
- let decodeResult = this.defaultResult();
2377
- decodeResult.decoder.name = this.name;
2378
- decodeResult.formatted.description = "Warning Message";
2379
- decodeResult.message = message;
2380
- const parts = message.text.split("/WN");
2381
- if (parts.length > 1) {
2382
- decodeResult.remaining.text = "";
2383
- const fields = parts[0].split("/");
2384
- for (let i = 1; i < fields.length; i++) {
2385
- const field = fields[i];
2386
- if (field.startsWith("PN")) {
2387
- processUnknown2(decodeResult, "/" + field);
2388
- } else {
2389
- processUnknown2(decodeResult, "/" + field);
2390
- }
2391
- }
2392
- const data = parts[1].substring(0, 20);
2393
- const msg = parts[1].substring(20);
2394
- const datetime = data.substring(0, 12);
2395
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2396
- processUnknown2(decodeResult, data.substring(12));
2397
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2398
- decodeResult.raw.warning_message = msg;
2399
- decodeResult.formatted.items.push({
2400
- type: "warning",
2401
- code: "WRN",
2402
- label: "Warning Message",
2403
- value: decodeResult.raw.warning_message
2404
- });
2405
- decodeResult.decoded = true;
2406
- decodeResult.decoder.decodeLevel = "partial";
2407
- } else {
2408
- if (options.debug) {
2409
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2410
- }
2411
- decodeResult.remaining.text = message.text;
2412
- decodeResult.decoded = false;
2413
- decodeResult.decoder.decodeLevel = "none";
2414
- }
2415
- return decodeResult;
2416
- }
2417
- };
2418
- function processUnknown2(decodeResult, value) {
2419
- decodeResult.remaining.text += value;
2420
- }
2421
-
2422
- // lib/utils/flight_plan_utils.ts
2423
- var FlightPlanUtils = class _FlightPlanUtils {
2424
- /**
2425
- * Processes flight plan data
2426
- *
2427
- * Expected format is [header, key1, val1, ... keyN, valN]
2428
- *
2429
- * @param decodeResult - results
2430
- * @param data - original message split by ':'
2431
- * @returns whether all fields were processed or not
2432
- */
2433
- static processFlightPlan(decodeResult, data) {
2434
- let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2435
- for (let i = 1; i < data.length; i += 2) {
2436
- const key = data[i];
2437
- const value = data[i + 1];
2438
- switch (key) {
2439
- case "A":
2440
- addProcedure(decodeResult, value, "arrival");
2441
- break;
2442
- case "AA":
2443
- addArrivalAirport(decodeResult, value);
2444
- break;
2445
- case "AP":
2446
- addProcedure(decodeResult, value, "approach");
2447
- break;
2448
- case "CR":
2449
- addCompanyRoute(decodeResult, value);
2450
- break;
2451
- case "D":
2452
- addProcedure(decodeResult, value, "departure");
2453
- break;
2454
- case "DA":
2455
- addDepartureAirport(decodeResult, value);
2456
- break;
2457
- case "F":
2458
- addRoute(decodeResult, value);
2459
- break;
2460
- case "R":
2461
- addRunway(decodeResult, value);
2462
- break;
2463
- default:
2464
- if (allKnownFields) {
2465
- decodeResult.remaining.text = "";
2466
- allKnownFields = false;
2467
- }
2468
- decodeResult.remaining.text += `:${key}:${value}`;
2469
- decodeResult.decoder.decodeLevel = "partial";
2470
- }
2471
- }
2472
- return allKnownFields;
2473
- }
2474
- static parseHeader(decodeResult, header) {
2475
- let allKnownFields = true;
2476
- if (header.startsWith("RF")) {
2477
- decodeResult.formatted.items.push({
2478
- type: "status",
2479
- code: "ROUTE_STATUS",
2480
- label: "Route Status",
2481
- value: "Route Filed"
2482
- });
2483
- decodeResult.raw.route_status = "RF";
2484
- if (header.length > 2) {
2485
- addRoute(decodeResult, header.substring(2));
2486
- }
2487
- } else if (header.startsWith("RP")) {
2488
- decodeResult.raw.route_status = "RP";
2489
- decodeResult.formatted.items.push({
2490
- type: "status",
2491
- code: "ROUTE_STATUS",
2492
- label: "Route Status",
2493
- value: "Route Planned"
2494
- });
2495
- decodeResult.raw.route_status = header;
2496
- } else if (header.startsWith("RI")) {
2497
- decodeResult.raw.route_status = "RI";
2498
- decodeResult.formatted.items.push({
2499
- type: "status",
2500
- code: "ROUTE_STATUS",
2501
- label: "Route Status",
2502
- value: "Route Inactive"
2503
- });
2504
- } else {
2505
- decodeResult.remaining.text += header;
2506
- allKnownFields = false;
2238
+ decodeResult.remaining.text += header;
2239
+ allKnownFields = false;
2507
2240
  }
2508
2241
  return allKnownFields;
2509
2242
  }
@@ -2522,13 +2255,7 @@ function addRunway(decodeResult, value) {
2522
2255
  }
2523
2256
  function addRoute(decodeResult, value) {
2524
2257
  const route = value.split(".");
2525
- decodeResult.raw.route = { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) };
2526
- decodeResult.formatted.items.push({
2527
- type: "aircraft_route",
2528
- code: "ROUTE",
2529
- label: "Aircraft Route",
2530
- value: RouteUtils.routeToString(decodeResult.raw.route)
2531
- });
2258
+ ResultFormatter.route(decodeResult, { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) });
2532
2259
  }
2533
2260
  function addProcedure(decodeResult, value, type) {
2534
2261
  if (decodeResult.raw.procedures === void 0) {
@@ -2578,257 +2305,652 @@ function addCompanyRoute(decodeResult, value) {
2578
2305
  });
2579
2306
  }
2580
2307
 
2581
- // lib/utils/h1_helper.ts
2582
- var H1Helper = class {
2583
- static decodeH1Message(decodeResult, message) {
2584
- const checksum = message.slice(-4);
2585
- const data = message.slice(0, message.length - 4);
2586
- const fields = data.split("/");
2587
- parseMessageType(decodeResult, fields[0]);
2588
- for (let i = 1; i < fields.length; ++i) {
2589
- if (fields[i].startsWith("FN")) {
2590
- decodeResult.raw.flight_number = fields[i].substring(2);
2591
- } else if (fields[i].startsWith("SN")) {
2592
- decodeResult.raw.serial_number = fields[i].substring(2);
2593
- } else if (fields[i].startsWith("DC")) {
2594
- processDC(decodeResult, fields[i].substring(2).split(","));
2595
- } else if (fields[i].startsWith("TS")) {
2596
- const ts = fields[i].substring(2).split(",");
2597
- let time = DateTimeUtils.convertDateTimeToEpoch(ts[0], ts[1]);
2598
- if (Number.isNaN(time)) {
2599
- const date = ts[1].substring(2, 4) + ts[1].substring(0, 2) + ts[1].substring(4, 6);
2600
- time = DateTimeUtils.convertDateTimeToEpoch(ts[0], date);
2601
- }
2602
- decodeResult.raw.message_date = ts[1];
2603
- decodeResult.raw.message_timestamp = time;
2604
- } else if (fields[i].startsWith("PS")) {
2605
- const pos = processPS(decodeResult, fields[i].substring(2).split(","));
2606
- } else if (fields[i].startsWith("DT")) {
2607
- const data2 = fields[i].substring(2).split(",");
2608
- processDT(decodeResult, data2);
2609
- } else if (fields[i].startsWith("ID")) {
2610
- processIdentification(decodeResult, fields[i].substring(2).split(","));
2611
- } else if (fields[i].startsWith("LR")) {
2612
- const data2 = fields[i].substring(2).split(",");
2613
- processLR(decodeResult, data2);
2614
- } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
2615
- FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2616
- } else if (fields[i].startsWith("PR")) {
2617
- decodeResult.remaining.text += "/" + fields[i];
2618
- } else if (fields[i].startsWith("AF")) {
2619
- processAirField(decodeResult, fields[i].substring(2).split(","));
2620
- } else if (fields[i].startsWith("TD")) {
2621
- processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2622
- } else if (fields[i].startsWith("FX")) {
2623
- decodeResult.raw.free_text = fields[i].substring(2);
2308
+ // lib/utils/h1_helper.ts
2309
+ var H1Helper = class {
2310
+ static decodeH1Message(decodeResult, message) {
2311
+ const checksum = message.slice(-4);
2312
+ const data = message.slice(0, message.length - 4);
2313
+ const fields = data.split("/");
2314
+ parseMessageType(decodeResult, fields[0]);
2315
+ for (let i = 1; i < fields.length; ++i) {
2316
+ if (fields[i].startsWith("FN")) {
2317
+ decodeResult.raw.flight_number = fields[i].substring(2);
2318
+ } else if (fields[i].startsWith("SN")) {
2319
+ decodeResult.raw.serial_number = fields[i].substring(2);
2320
+ } else if (fields[i].startsWith("DC")) {
2321
+ processDC(decodeResult, fields[i].substring(2).split(","));
2322
+ } else if (fields[i].startsWith("TS")) {
2323
+ const ts = fields[i].substring(2).split(",");
2324
+ let time = DateTimeUtils.convertDateTimeToEpoch(ts[0], ts[1]);
2325
+ if (Number.isNaN(time)) {
2326
+ const date = ts[1].substring(2, 4) + ts[1].substring(0, 2) + ts[1].substring(4, 6);
2327
+ time = DateTimeUtils.convertDateTimeToEpoch(ts[0], date);
2328
+ }
2329
+ decodeResult.raw.message_date = ts[1];
2330
+ decodeResult.raw.message_timestamp = time;
2331
+ } else if (fields[i].startsWith("PS")) {
2332
+ const pos = processPS(decodeResult, fields[i].substring(2).split(","));
2333
+ } else if (fields[i].startsWith("DT")) {
2334
+ const data2 = fields[i].substring(2).split(",");
2335
+ processDT(decodeResult, data2);
2336
+ } else if (fields[i].startsWith("ID")) {
2337
+ processIdentification(decodeResult, fields[i].substring(2).split(","));
2338
+ } else if (fields[i].startsWith("LR")) {
2339
+ const data2 = fields[i].substring(2).split(",");
2340
+ processLR(decodeResult, data2);
2341
+ } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
2342
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2343
+ } else if (fields[i].startsWith("PR")) {
2344
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2345
+ } else if (fields[i].startsWith("AF")) {
2346
+ processAirField(decodeResult, fields[i].substring(2).split(","));
2347
+ } else if (fields[i].startsWith("TD")) {
2348
+ processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2349
+ } else if (fields[i].startsWith("FX")) {
2350
+ ResultFormatter.freetext(decodeResult, fields[i].substring(2));
2351
+ } else if (fields[i].startsWith("ET")) {
2352
+ if (fields[i].length === 7) {
2353
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3) + "00"));
2354
+ } else if (fields[i].length === 8) {
2355
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4) + "00"));
2356
+ } else {
2357
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2358
+ }
2359
+ } else {
2360
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2361
+ }
2362
+ }
2363
+ if (decodeResult.formatted.items.length > 0) {
2364
+ ResultFormatter.checksum(decodeResult, checksum);
2365
+ }
2366
+ return true;
2367
+ }
2368
+ };
2369
+ function processAirField(decodeResult, data) {
2370
+ if (data.length === 2) {
2371
+ ResultFormatter.departureAirport(decodeResult, data[0]);
2372
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
2373
+ } else {
2374
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
2375
+ }
2376
+ }
2377
+ function processTimeOfDeparture(decodeResult, data) {
2378
+ if (data.length === 2) {
2379
+ decodeResult.raw.plannedDepartureTime = data[0];
2380
+ decodeResult.formatted.items.push({
2381
+ type: "ptd",
2382
+ code: "ptd",
2383
+ label: "Planned Departure Time",
2384
+ value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
2385
+ });
2386
+ decodeResult.raw.plannedDepartureTime = data[1];
2387
+ decodeResult.formatted.items.push({
2388
+ type: "etd",
2389
+ code: "etd",
2390
+ label: "Estimated Departure Time",
2391
+ value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2392
+ });
2393
+ } else {
2394
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
2395
+ }
2396
+ }
2397
+ function processIdentification(decodeResult, data) {
2398
+ ResultFormatter.tail(decodeResult, data[0]);
2399
+ if (data.length > 1) {
2400
+ decodeResult.raw.flight_number = data[1];
2401
+ }
2402
+ if (data.length > 2) {
2403
+ decodeResult.raw.mission_number = data[2];
2404
+ }
2405
+ }
2406
+ function processDT(decodeResult, data) {
2407
+ if (!decodeResult.raw.arrival_icao) {
2408
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
2409
+ } else if (decodeResult.raw.arrival_icao != data[0]) {
2410
+ ResultFormatter.unknownArr(decodeResult, data);
2411
+ }
2412
+ if (data.length > 1) {
2413
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
2414
+ }
2415
+ if (data.length > 2) {
2416
+ ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2417
+ }
2418
+ if (data.length > 3) {
2419
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2420
+ }
2421
+ if (data.length > 4) {
2422
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2423
+ }
2424
+ if (data.length > 5) {
2425
+ ResultFormatter.unknownArr(decodeResult, data);
2426
+ }
2427
+ }
2428
+ function processLR(decodeResult, data) {
2429
+ if (data.length === 19) {
2430
+ ResultFormatter.unknown(decodeResult, data[1]);
2431
+ ResultFormatter.flightNumber(decodeResult, data[2]);
2432
+ ResultFormatter.departureAirport(decodeResult, data[3]);
2433
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
2434
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
2435
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2436
+ } else {
2437
+ ResultFormatter.unknown(decodeResult, data.join(","));
2438
+ }
2439
+ }
2440
+ function parseMessageType(decodeResult, messageType) {
2441
+ const parts = messageType.split("#");
2442
+ if (parts.length == 1) {
2443
+ const type = parts[0].substring(0, 3);
2444
+ if (type === "POS" && parts[0].length !== 3) {
2445
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2446
+ }
2447
+ return processMessageType(decodeResult, type);
2448
+ } else if (parts.length == 2) {
2449
+ if (parts[0].length > 0) {
2450
+ ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2451
+ decodeResult.raw.flight_number = parts[0].substring(3);
2452
+ ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2453
+ }
2454
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2455
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2456
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2457
+ }
2458
+ processMessageType(decodeResult, type);
2459
+ } else {
2460
+ ResultFormatter.unknown(decodeResult, messageType);
2461
+ }
2462
+ }
2463
+ function processMessageType(decodeResult, type) {
2464
+ if (type === "FPN") {
2465
+ decodeResult.formatted.description = "Flight Plan";
2466
+ } else if (type === "FTX") {
2467
+ decodeResult.formatted.description = "Free Text";
2468
+ } else if (type === "INI") {
2469
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2470
+ } else if (type === "POS") {
2471
+ decodeResult.formatted.description = "Position Report";
2472
+ } else if (type === "PRG") {
2473
+ decodeResult.formatted.description = "Progress Report";
2474
+ } else {
2475
+ decodeResult.formatted.description = "Unknown H1 Message";
2476
+ }
2477
+ }
2478
+ function processDC(decodeResult, data) {
2479
+ decodeResult.raw.message_date = data[0];
2480
+ if (data.length === 1) {
2481
+ } else if (data.length === 2) {
2482
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2483
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2484
+ decodeResult.raw.message_timestamp = time;
2485
+ }
2486
+ }
2487
+ function processPS(decodeResult, data) {
2488
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2489
+ if (position) {
2490
+ decodeResult.raw.position = position;
2491
+ decodeResult.formatted.items.push({
2492
+ type: "aircraft_position",
2493
+ code: "POS",
2494
+ label: "Aircraft Position",
2495
+ value: CoordinateUtils.coordinateString(position)
2496
+ });
2497
+ }
2498
+ if (data.length === 9) {
2499
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2500
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2501
+ ResultFormatter.temperature(decodeResult, data[6]);
2502
+ ResultFormatter.unknown(decodeResult, data[7]);
2503
+ ResultFormatter.unknown(decodeResult, data[8]);
2504
+ }
2505
+ if (data.length === 14) {
2506
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2507
+ processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2508
+ ResultFormatter.temperature(decodeResult, data[7]);
2509
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2510
+ ResultFormatter.unknown(decodeResult, data[1]);
2511
+ ResultFormatter.unknown(decodeResult, data[8]);
2512
+ ResultFormatter.unknown(decodeResult, data[9]);
2513
+ ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2514
+ }
2515
+ }
2516
+ function processPosition2(decodeResult, data) {
2517
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2518
+ if (position) {
2519
+ decodeResult.raw.position = position;
2520
+ decodeResult.formatted.items.push({
2521
+ type: "aircraft_position",
2522
+ code: "POS",
2523
+ label: "Aircraft Position",
2524
+ value: CoordinateUtils.coordinateString(position)
2525
+ });
2526
+ }
2527
+ if (data.length >= 10) {
2528
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2529
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2530
+ ResultFormatter.temperature(decodeResult, data[7]);
2531
+ ResultFormatter.unknown(decodeResult, data[8]);
2532
+ ResultFormatter.unknown(decodeResult, data[9]);
2533
+ }
2534
+ if (data.length >= 14) {
2535
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2536
+ ResultFormatter.unknown(decodeResult, data[11]);
2537
+ ResultFormatter.unknown(decodeResult, data[12]);
2538
+ ResultFormatter.unknown(decodeResult, data[13]);
2539
+ }
2540
+ }
2541
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
2542
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2543
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2544
+ const timeFormat = date ? "epoch" : "tod";
2545
+ const lastWaypoint = RouteUtils.getWaypoint(last);
2546
+ lastWaypoint.time = lastTime;
2547
+ lastWaypoint.timeFormat = timeFormat;
2548
+ const nextWaypoint = RouteUtils.getWaypoint(next);
2549
+ nextWaypoint.time = nextTime;
2550
+ nextWaypoint.timeFormat = timeFormat;
2551
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2552
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2553
+ decodeResult.raw.route = { waypoints };
2554
+ decodeResult.formatted.items.push({
2555
+ type: "aircraft_route",
2556
+ code: "ROUTE",
2557
+ label: "Aircraft Route",
2558
+ value: RouteUtils.routeToString(decodeResult.raw.route)
2559
+ });
2560
+ }
2561
+
2562
+ // lib/plugins/Label_4J_POS.ts
2563
+ var Label_4J_POS = class extends DecoderPlugin {
2564
+ name = "label-4j-pos";
2565
+ qualifiers() {
2566
+ return {
2567
+ labels: ["4J"],
2568
+ preambles: ["POS/"]
2569
+ };
2570
+ }
2571
+ // copied from Label_H1.ts since i don't really want to have to have
2572
+ // something named like that decode more than 1 type
2573
+ // if we figure out a good name, i'll combine them
2574
+ decode(message, options = {}) {
2575
+ let decodeResult = this.defaultResult();
2576
+ decodeResult.decoder.name = this.name;
2577
+ decodeResult.message = message;
2578
+ const msg = message.text.replace(/\n|\r/g, "");
2579
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2580
+ decodeResult.decoded = decoded;
2581
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2582
+ if (decodeResult.formatted.items.length === 0) {
2583
+ if (options.debug) {
2584
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2585
+ }
2586
+ ResultFormatter.unknown(decodeResult, message.text);
2587
+ decodeResult.decoded = false;
2588
+ decodeResult.decoder.decodeLevel = "none";
2589
+ }
2590
+ return decodeResult;
2591
+ }
2592
+ };
2593
+
2594
+ // lib/plugins/Label_4N.ts
2595
+ var Label_4N = class extends DecoderPlugin {
2596
+ name = "label-4n";
2597
+ qualifiers() {
2598
+ return {
2599
+ labels: ["4N"]
2600
+ };
2601
+ }
2602
+ decode(message, options = {}) {
2603
+ const decodeResult = this.defaultResult();
2604
+ decodeResult.decoder.name = this.name;
2605
+ decodeResult.message = message;
2606
+ decodeResult.formatted.description = "Airline Defined";
2607
+ let text = message.text;
2608
+ if (text.match(/^M\d{2}A\w{6}/)) {
2609
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2610
+ text = text.substring(10);
2611
+ }
2612
+ decodeResult.decoded = true;
2613
+ const fields = text.split(",");
2614
+ if (text.length === 51) {
2615
+ decodeResult.raw.day_of_month = text.substring(0, 2);
2616
+ ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
2617
+ ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
2618
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
2619
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2620
+ ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
2621
+ } else if (fields.length === 33) {
2622
+ decodeResult.raw.date = fields[3];
2623
+ if (fields[1] === "B") {
2624
+ ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
2625
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
2626
+ }
2627
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
2628
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
2629
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
2630
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
2631
+ if (fields[12].length > 1) {
2632
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2633
+ }
2634
+ ResultFormatter.checksum(decodeResult, fields[32]);
2635
+ ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
2636
+ } else {
2637
+ decodeResult.decoded = false;
2638
+ ResultFormatter.unknown(decodeResult, text);
2639
+ }
2640
+ if (decodeResult.decoded) {
2641
+ if (!decodeResult.remaining.text)
2642
+ decodeResult.decoder.decodeLevel = "full";
2643
+ else
2644
+ decodeResult.decoder.decodeLevel = "partial";
2645
+ } else {
2646
+ decodeResult.decoder.decodeLevel = "none";
2647
+ }
2648
+ return decodeResult;
2649
+ }
2650
+ };
2651
+
2652
+ // lib/plugins/Label_80.ts
2653
+ var Label_80 = class extends DecoderPlugin {
2654
+ name = "label-80";
2655
+ descriptions = {
2656
+ ALT: "Altitude",
2657
+ DWND: "Wind Direction",
2658
+ ETA: "Estimated Time of Arrival",
2659
+ FOB: "Fuel on Board",
2660
+ FL: "Flight Level",
2661
+ HDG: "Heading",
2662
+ MCH: "Aircraft Speed",
2663
+ NWYP: "Next Waypoint",
2664
+ POS: "Aircraft Position",
2665
+ SAT: "Static Air Temperature",
2666
+ SWND: "Wind Speed",
2667
+ TAS: "True Airspeed",
2668
+ WYP: "Waypoint"
2669
+ };
2670
+ qualifiers() {
2671
+ return {
2672
+ labels: ["80"],
2673
+ preambles: ["3N01 POSRPT"]
2674
+ };
2675
+ }
2676
+ decode(message, options = {}) {
2677
+ const decodeResult = this.defaultResult();
2678
+ decodeResult.decoder.name = this.name;
2679
+ decodeResult.formatted.description = "Airline Defined Position Report";
2680
+ const parts = message.text.split("\n");
2681
+ let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
2682
+ let results = parts[0].match(posRptRegex);
2683
+ if (!results?.groups) {
2684
+ decodeResult.decoded = false;
2685
+ decodeResult.decoder.decodeLevel = "none";
2686
+ return decodeResult;
2687
+ }
2688
+ if (results && results.length > 0) {
2689
+ ResultFormatter.departureAirport(decodeResult, results.groups.orig);
2690
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
2691
+ ResultFormatter.tail(decodeResult, results.groups.tail);
2692
+ if (results.groups.agate) {
2693
+ decodeResult.raw.arrival_gate = results.groups.agate;
2624
2694
  decodeResult.formatted.items.push({
2625
- type: "text",
2626
- code: "TEXT",
2627
- label: "Free Text",
2628
- value: decodeResult.raw.free_text
2695
+ type: "arrival_gate",
2696
+ code: "ARG",
2697
+ label: "Arrival Gate",
2698
+ value: `${results.groups.agate}`
2699
+ });
2700
+ decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
2701
+ decodeResult.formatted.items.push({
2702
+ type: "scheduled_time_of_arrival",
2703
+ code: "STA",
2704
+ label: "Scheduled Time of Arrival",
2705
+ value: `${results.groups.sta}`
2629
2706
  });
2630
- } else {
2631
- decodeResult.remaining.text += "/" + fields[i];
2632
2707
  }
2708
+ posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
2709
+ const remainingParts = parts.slice(1);
2710
+ for (const part of remainingParts) {
2711
+ const matches = part.matchAll(posRptRegex);
2712
+ for (const match of matches) {
2713
+ switch (match.groups?.field) {
2714
+ case "ALT": {
2715
+ ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2716
+ break;
2717
+ }
2718
+ case "DWND": {
2719
+ decodeResult.raw.wind_direction = Number(match.groups.value);
2720
+ decodeResult.formatted.items.push({
2721
+ type: "wind_direction",
2722
+ code: "DWND",
2723
+ label: this.descriptions[match.groups.field],
2724
+ value: decodeResult.raw.wind_direction
2725
+ });
2726
+ break;
2727
+ }
2728
+ case "FL": {
2729
+ const flight_level = Number(match.groups.value);
2730
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
2731
+ break;
2732
+ }
2733
+ case "FOB": {
2734
+ const fob = Number(match.groups.value);
2735
+ if (!isNaN(fob)) {
2736
+ ResultFormatter.currentFuel(decodeResult, fob);
2737
+ }
2738
+ break;
2739
+ }
2740
+ case "HDG": {
2741
+ ResultFormatter.heading(decodeResult, Number(match.groups.value));
2742
+ break;
2743
+ }
2744
+ case "MCH": {
2745
+ decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2746
+ decodeResult.formatted.items.push({
2747
+ type: "mach",
2748
+ code: "MCH",
2749
+ label: this.descriptions[match.groups.field],
2750
+ value: `${decodeResult.raw.mach} Mach`
2751
+ });
2752
+ break;
2753
+ }
2754
+ case "NWYP": {
2755
+ decodeResult.raw.next_waypoint = match.groups.value;
2756
+ decodeResult.formatted.items.push({
2757
+ type: "next_waypoint",
2758
+ code: "NWYP",
2759
+ label: this.descriptions[match.groups.field],
2760
+ value: decodeResult.raw.next_waypoint
2761
+ });
2762
+ break;
2763
+ }
2764
+ case "POS": {
2765
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2766
+ const posResult = match.groups.value.match(posRegex);
2767
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2768
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2769
+ const position = {
2770
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2771
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2772
+ };
2773
+ ResultFormatter.position(decodeResult, position);
2774
+ break;
2775
+ }
2776
+ case "SWND": {
2777
+ decodeResult.raw.wind_speed = Number(match.groups.value);
2778
+ decodeResult.formatted.items.push({
2779
+ type: "wind_speed",
2780
+ code: "SWND",
2781
+ label: this.descriptions[match.groups.field],
2782
+ value: decodeResult.raw.wind_speed
2783
+ });
2784
+ break;
2785
+ }
2786
+ default: {
2787
+ if (match.groups?.field != void 0) {
2788
+ const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2789
+ decodeResult.formatted.items.push({
2790
+ type: match.groups.field,
2791
+ code: match.groups.field,
2792
+ label: description || `Unknown (${match.groups.field})`,
2793
+ value: `${match.groups.value}`
2794
+ });
2795
+ }
2796
+ }
2797
+ }
2798
+ }
2799
+ }
2800
+ decodeResult.decoded = true;
2801
+ decodeResult.decoder.decodeLevel = "partial";
2633
2802
  }
2634
- if (decodeResult.formatted.items.length > 0) {
2635
- ResultFormatter.checksum(decodeResult, checksum);
2636
- }
2637
- return true;
2803
+ return decodeResult;
2638
2804
  }
2639
2805
  };
2640
- function processAirField(decodeResult, data) {
2641
- if (data.length === 2) {
2642
- ResultFormatter.departureAirport(decodeResult, data[0]);
2643
- ResultFormatter.arrivalAirport(decodeResult, data[1]);
2644
- } else {
2645
- decodeResult.remaining.text += "AF/" + data.join(",");
2646
- }
2647
- }
2648
- function processTimeOfDeparture(decodeResult, data) {
2649
- if (data.length === 2) {
2650
- decodeResult.raw.plannedDepartureTime = data[0];
2651
- decodeResult.formatted.items.push({
2652
- type: "ptd",
2653
- code: "ptd",
2654
- label: "Planned Departure Time",
2655
- value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
2656
- });
2657
- decodeResult.raw.plannedDepartureTime = data[1];
2658
- decodeResult.formatted.items.push({
2659
- type: "etd",
2660
- code: "etd",
2661
- label: "Estimated Departure Time",
2662
- value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2663
- });
2664
- } else {
2665
- decodeResult.remaining.text += "/TD" + data.join(",");
2666
- }
2667
- }
2668
- function processIdentification(decodeResult, data) {
2669
- ResultFormatter.tail(decodeResult, data[0]);
2670
- if (data.length > 1) {
2671
- decodeResult.raw.flight_number = data[1];
2672
- }
2673
- if (data.length > 2) {
2674
- decodeResult.raw.mission_number = data[2];
2675
- }
2676
- }
2677
- function processDT(decodeResult, data) {
2678
- if (!decodeResult.raw.arrival_icao) {
2679
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2680
- } else if (decodeResult.raw.arrival_icao != data[0]) {
2681
- decodeResult.remaining.text += "/" + data;
2682
- }
2683
- if (data.length > 1) {
2684
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2685
- }
2686
- if (data.length > 2) {
2687
- ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2688
- }
2689
- if (data.length > 3) {
2690
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2691
- }
2692
- if (data.length > 4) {
2693
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2694
- }
2695
- if (data.length > 5) {
2696
- decodeResult.remaining.text += "," + data.slice(5).join(",");
2697
- }
2698
- }
2699
- function processLR(decodeResult, data) {
2700
- if (data.length === 19) {
2701
- ResultFormatter.unknown(decodeResult, data[1]);
2702
- ResultFormatter.flightNumber(decodeResult, data[2]);
2703
- ResultFormatter.departureAirport(decodeResult, data[3]);
2704
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
2705
- ResultFormatter.arrivalRunway(decodeResult, data[5]);
2706
- ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2707
- } else {
2708
- ResultFormatter.unknown(decodeResult, data.join(","));
2806
+
2807
+ // lib/plugins/Label_83.ts
2808
+ var Label_83 = class extends DecoderPlugin {
2809
+ name = "label-83";
2810
+ qualifiers() {
2811
+ return {
2812
+ labels: ["83"]
2813
+ };
2709
2814
  }
2710
- }
2711
- function parseMessageType(decodeResult, messageType) {
2712
- const parts = messageType.split("#");
2713
- if (parts.length == 1) {
2714
- const type = parts[0].substring(0, 3);
2715
- if (type === "POS" && parts[0].length !== 3) {
2716
- processPosition2(decodeResult, parts[0].substring(3).split(","));
2815
+ decode(message, options = {}) {
2816
+ const decodeResult = this.defaultResult();
2817
+ decodeResult.decoder.name = this.name;
2818
+ decodeResult.message = message;
2819
+ decodeResult.formatted.description = "Airline Defined";
2820
+ let text = message.text;
2821
+ if (text.match(/^M\d{2}A\w{6}/)) {
2822
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2823
+ text = text.substring(10);
2717
2824
  }
2718
- return processMessageType(decodeResult, type);
2719
- } else if (parts.length == 2) {
2720
- if (parts[0].length > 0) {
2721
- decodeResult.remaining.text += parts[0].substring(0, 3);
2722
- decodeResult.raw.flight_number = parts[0].substring(3);
2723
- decodeResult.remaining.text += "#" + (parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3));
2825
+ decodeResult.decoded = true;
2826
+ if (text.substring(0, 10) === "4DH3 ETAT2") {
2827
+ const fields = text.split(/\s+/);
2828
+ if (fields[2].length > 5) {
2829
+ decodeResult.raw.day_of_month = fields[2].substring(5);
2830
+ }
2831
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
2832
+ const subfields = fields[3].split("/");
2833
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
2834
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2835
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2836
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2837
+ } else if (text.substring(0, 5) === "001PR") {
2838
+ decodeResult.raw.day_of_month = text.substring(5, 7);
2839
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2840
+ if (position) {
2841
+ ResultFormatter.position(decodeResult, position);
2842
+ }
2843
+ ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
2844
+ ResultFormatter.unknown(decodeResult, text.substring(33));
2845
+ } else {
2846
+ const fields = text.replace(/\s/g, "").split(",");
2847
+ if (fields.length === 9) {
2848
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
2849
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2850
+ decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2851
+ decodeResult.raw.time = fields[2].substring(2);
2852
+ ResultFormatter.position(
2853
+ decodeResult,
2854
+ {
2855
+ latitude: Number(fields[3].replace(/\s/g, "")),
2856
+ longitude: Number(fields[4].replace(/\s/g, ""))
2857
+ }
2858
+ );
2859
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2860
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2861
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
2862
+ ResultFormatter.unknown(decodeResult, fields[8]);
2863
+ } else {
2864
+ decodeResult.decoded = false;
2865
+ ResultFormatter.unknown(decodeResult, message.text);
2866
+ }
2724
2867
  }
2725
- const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2726
- if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2727
- processPosition2(decodeResult, parts[1].substring(6).split(","));
2868
+ if (decodeResult.decoded) {
2869
+ if (!decodeResult.remaining.text)
2870
+ decodeResult.decoder.decodeLevel = "full";
2871
+ else
2872
+ decodeResult.decoder.decodeLevel = "partial";
2873
+ } else {
2874
+ decodeResult.decoder.decodeLevel = "none";
2728
2875
  }
2729
- processMessageType(decodeResult, type);
2730
- } else {
2731
- decodeResult.remaining.text += messageType;
2732
- }
2733
- }
2734
- function processMessageType(decodeResult, type) {
2735
- if (type === "FPN") {
2736
- decodeResult.formatted.description = "Flight Plan";
2737
- } else if (type === "FTX") {
2738
- decodeResult.formatted.description = "Free Text";
2739
- } else if (type === "INI") {
2740
- decodeResult.formatted.description = "Flight Plan Initial Report";
2741
- } else if (type === "POS") {
2742
- decodeResult.formatted.description = "Position Report";
2743
- } else if (type === "PRG") {
2744
- decodeResult.formatted.description = "Progress Report";
2745
- } else {
2746
- decodeResult.formatted.description = "Unknown H1 Message";
2747
- }
2748
- }
2749
- function processDC(decodeResult, data) {
2750
- decodeResult.raw.message_date = data[0];
2751
- if (data.length === 1) {
2752
- } else if (data.length === 2) {
2753
- const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2754
- const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2755
- decodeResult.raw.message_timestamp = time;
2876
+ return decodeResult;
2756
2877
  }
2757
- }
2758
- function processPS(decodeResult, data) {
2759
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2760
- if (position) {
2761
- decodeResult.raw.position = position;
2762
- decodeResult.formatted.items.push({
2763
- type: "aircraft_position",
2764
- code: "POS",
2765
- label: "Aircraft Position",
2766
- value: CoordinateUtils.coordinateString(position)
2767
- });
2878
+ };
2879
+
2880
+ // lib/plugins/Label_8E.ts
2881
+ var Label_8E = class extends DecoderPlugin {
2882
+ name = "label-8e";
2883
+ qualifiers() {
2884
+ return {
2885
+ labels: ["8E"]
2886
+ };
2768
2887
  }
2769
- if (data.length === 9) {
2770
- processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2771
- ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2772
- ResultFormatter.temperature(decodeResult, data[6]);
2773
- ResultFormatter.unknown(decodeResult, data[7]);
2774
- ResultFormatter.unknown(decodeResult, data[8]);
2888
+ decode(message, options = {}) {
2889
+ const decodeResult = this.defaultResult();
2890
+ decodeResult.decoder.name = this.name;
2891
+ decodeResult.formatted.description = "ETA Report";
2892
+ decodeResult.message = message;
2893
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2894
+ const results = message.text.match(regex);
2895
+ if (results?.groups) {
2896
+ if (options.debug) {
2897
+ console.log(`Label 8E ETA: groups`);
2898
+ console.log(results.groups);
2899
+ }
2900
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2901
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2902
+ }
2903
+ decodeResult.decoded = true;
2904
+ decodeResult.decoder.decodeLevel = "full";
2905
+ return decodeResult;
2775
2906
  }
2776
- if (data.length === 14) {
2777
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2778
- processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2779
- ResultFormatter.temperature(decodeResult, data[7]);
2780
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2781
- ResultFormatter.unknown(decodeResult, data[1]);
2782
- ResultFormatter.unknown(decodeResult, data[8]);
2783
- ResultFormatter.unknown(decodeResult, data[9]);
2784
- ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2907
+ };
2908
+
2909
+ // lib/plugins/Label_B6.ts
2910
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
2911
+ name = "label-b6-forwardslash";
2912
+ qualifiers() {
2913
+ return {
2914
+ labels: ["B6"],
2915
+ preambles: ["/"]
2916
+ };
2785
2917
  }
2786
- }
2787
- function processPosition2(decodeResult, data) {
2788
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2789
- if (position) {
2790
- decodeResult.raw.position = position;
2791
- decodeResult.formatted.items.push({
2792
- type: "aircraft_position",
2793
- code: "POS",
2794
- label: "Aircraft Position",
2795
- value: CoordinateUtils.coordinateString(position)
2796
- });
2918
+ decode(message, options = {}) {
2919
+ const decodeResult = this.defaultResult();
2920
+ decodeResult.decoder.name = this.name;
2921
+ decodeResult.formatted.description = "CPDLC Message";
2922
+ decodeResult.message = message;
2923
+ if (options.debug) {
2924
+ console.log("CPDLC: " + message);
2925
+ }
2926
+ return decodeResult;
2797
2927
  }
2798
- if (data.length >= 10) {
2799
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2800
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2801
- ResultFormatter.temperature(decodeResult, data[7]);
2802
- ResultFormatter.unknown(decodeResult, data[8]);
2803
- ResultFormatter.unknown(decodeResult, data[9]);
2928
+ };
2929
+
2930
+ // lib/plugins/Label_ColonComma.ts
2931
+ var Label_ColonComma = class extends DecoderPlugin {
2932
+ name = "label-colon-comma";
2933
+ qualifiers() {
2934
+ return {
2935
+ labels: [":;"]
2936
+ };
2804
2937
  }
2805
- if (data.length >= 14) {
2806
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2807
- ResultFormatter.unknown(decodeResult, data[11]);
2808
- ResultFormatter.unknown(decodeResult, data[12]);
2809
- ResultFormatter.unknown(decodeResult, data[13]);
2938
+ decode(message, options = {}) {
2939
+ const decodeResult = this.defaultResult();
2940
+ decodeResult.decoder.name = this.name;
2941
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
2942
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2943
+ decodeResult.formatted.items.push({
2944
+ type: "frequency",
2945
+ label: "Frequency",
2946
+ value: `${decodeResult.raw.frequency} MHz`,
2947
+ code: "FREQ"
2948
+ });
2949
+ decodeResult.decoded = true;
2950
+ decodeResult.decoder.decodeLevel = "full";
2951
+ return decodeResult;
2810
2952
  }
2811
- }
2812
- function processRoute(decodeResult, last, time, next, eta, then, date) {
2813
- const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2814
- const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2815
- const timeFormat = date ? "epoch" : "tod";
2816
- const lastWaypoint = RouteUtils.getWaypoint(last);
2817
- lastWaypoint.time = lastTime;
2818
- lastWaypoint.timeFormat = timeFormat;
2819
- const nextWaypoint = RouteUtils.getWaypoint(next);
2820
- nextWaypoint.time = nextTime;
2821
- nextWaypoint.timeFormat = timeFormat;
2822
- const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2823
- const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2824
- decodeResult.raw.route = { waypoints };
2825
- decodeResult.formatted.items.push({
2826
- type: "aircraft_route",
2827
- code: "ROUTE",
2828
- label: "Aircraft Route",
2829
- value: RouteUtils.routeToString(decodeResult.raw.route)
2830
- });
2831
- }
2953
+ };
2832
2954
 
2833
2955
  // lib/plugins/Label_H1.ts
2834
2956
  var Label_H1 = class extends DecoderPlugin {
@@ -2842,16 +2964,205 @@ var Label_H1 = class extends DecoderPlugin {
2842
2964
  let decodeResult = this.defaultResult();
2843
2965
  decodeResult.decoder.name = this.name;
2844
2966
  decodeResult.message = message;
2845
- decodeResult.remaining.text = "";
2846
2967
  const msg = message.text.replace(/\n|\r/g, "");
2847
2968
  const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2848
2969
  decodeResult.decoded = decoded;
2849
- decodeResult.decoder.decodeLevel = decodeResult.remaining.text.length === 0 ? "full" : "partial";
2970
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2850
2971
  if (decodeResult.formatted.items.length === 0) {
2851
2972
  if (options.debug) {
2852
2973
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2853
2974
  }
2854
- decodeResult.remaining.text = message.text;
2975
+ ResultFormatter.unknown(decodeResult, message.text);
2976
+ decodeResult.decoded = false;
2977
+ decodeResult.decoder.decodeLevel = "none";
2978
+ }
2979
+ return decodeResult;
2980
+ }
2981
+ };
2982
+
2983
+ // lib/plugins/Label_H1_FLR.ts
2984
+ var Label_H1_FLR = class extends DecoderPlugin {
2985
+ name = "label-h1-flr";
2986
+ qualifiers() {
2987
+ return {
2988
+ labels: ["H1"],
2989
+ preambles: ["FLR", "#CFBFLR"]
2990
+ };
2991
+ }
2992
+ decode(message, options = {}) {
2993
+ let decodeResult = this.defaultResult();
2994
+ decodeResult.decoder.name = this.name;
2995
+ decodeResult.formatted.description = "Fault Log Report";
2996
+ decodeResult.message = message;
2997
+ const parts = message.text.split("/FR");
2998
+ if (parts.length > 1) {
2999
+ const fields = parts[0].split("/");
3000
+ for (let i = 1; i < fields.length; i++) {
3001
+ const field = fields[i];
3002
+ ResultFormatter.unknown(decodeResult, field, "/");
3003
+ }
3004
+ const data = parts[1].substring(0, 20);
3005
+ const msg = parts[1].substring(20);
3006
+ const datetime = data.substring(0, 12);
3007
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
3008
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
3009
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
3010
+ decodeResult.raw.fault_message = msg;
3011
+ decodeResult.formatted.items.push({
3012
+ type: "fault",
3013
+ code: "FR",
3014
+ label: "Fault Report",
3015
+ value: decodeResult.raw.fault_message
3016
+ });
3017
+ decodeResult.decoded = true;
3018
+ decodeResult.decoder.decodeLevel = "partial";
3019
+ } else {
3020
+ if (options.debug) {
3021
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
3022
+ }
3023
+ ResultFormatter.unknown(decodeResult, message.text);
3024
+ decodeResult.decoded = false;
3025
+ decodeResult.decoder.decodeLevel = "none";
3026
+ }
3027
+ return decodeResult;
3028
+ }
3029
+ };
3030
+
3031
+ // lib/plugins/Label_H1_OHMA.ts
3032
+ var zlib = __toESM(require("minizlib"));
3033
+ var Label_H1_OHMA = class extends DecoderPlugin {
3034
+ name = "label-h1-ohma";
3035
+ qualifiers() {
3036
+ return {
3037
+ labels: ["H1"],
3038
+ preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
3039
+ };
3040
+ }
3041
+ decode(message, options = {}) {
3042
+ let decodeResult = this.defaultResult();
3043
+ decodeResult.decoder.name = this.name;
3044
+ decodeResult.formatted.description = "OHMA Message";
3045
+ decodeResult.message = message;
3046
+ const data = message.text.split("OHMA")[1];
3047
+ try {
3048
+ const compressedBuffer = Buffer.from(data, "base64");
3049
+ const decompress = new zlib.Inflate({ windowBits: 15 });
3050
+ decompress.write(compressedBuffer);
3051
+ decompress.flush(zlib.constants.Z_SYNC_FLUSH);
3052
+ const result = decompress.read();
3053
+ const jsonText = result.toString();
3054
+ let formattedMsg;
3055
+ let jsonMessage;
3056
+ try {
3057
+ jsonMessage = JSON.parse(jsonText).message;
3058
+ } catch {
3059
+ jsonMessage = jsonText;
3060
+ }
3061
+ try {
3062
+ const ohmaMsg = JSON.parse(jsonMessage);
3063
+ formattedMsg = JSON.stringify(ohmaMsg, null, 2);
3064
+ } catch {
3065
+ formattedMsg = jsonMessage;
3066
+ }
3067
+ decodeResult.decoded = true;
3068
+ decodeResult.decoder.decodeLevel = "full";
3069
+ decodeResult.raw.ohma = jsonText;
3070
+ decodeResult.formatted.items.push({
3071
+ type: "ohma",
3072
+ code: "OHMA",
3073
+ label: "OHMA Downlink",
3074
+ value: formattedMsg
3075
+ });
3076
+ } catch (e) {
3077
+ if (options.debug) {
3078
+ console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
3079
+ }
3080
+ ResultFormatter.unknown(decodeResult, message.text);
3081
+ decodeResult.decoded = false;
3082
+ decodeResult.decoder.decodeLevel = "none";
3083
+ }
3084
+ return decodeResult;
3085
+ }
3086
+ };
3087
+
3088
+ // lib/plugins/Label_H1_StarPOS.ts
3089
+ var Label_H1_StarPOS = class extends DecoderPlugin {
3090
+ name = "label-h1-star-pos";
3091
+ qualifiers() {
3092
+ return {
3093
+ labels: ["H1"],
3094
+ preambles: ["*POS"]
3095
+ };
3096
+ }
3097
+ decode(message, options = {}) {
3098
+ let decodeResult = this.defaultResult();
3099
+ decodeResult.decoder.name = this.name;
3100
+ decodeResult.formatted.description = "Position Report";
3101
+ decodeResult.message = message;
3102
+ const msg = message.text;
3103
+ if (msg.length !== 43 || !msg.startsWith("*POS")) {
3104
+ if (options.debug) {
3105
+ console.log(`Decoder: Unknown H1 message: ${msg}`);
3106
+ }
3107
+ ResultFormatter.unknown(decodeResult, msg);
3108
+ decodeResult.decoded = false;
3109
+ decodeResult.decoder.decodeLevel = "none";
3110
+ return decodeResult;
3111
+ }
3112
+ decodeResult.raw.month = Number(msg.substring(4, 6));
3113
+ decodeResult.raw.day_of_month = Number(msg.substring(6, 8));
3114
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12) + "00"));
3115
+ ResultFormatter.position(decodeResult, {
3116
+ // Deg Min, no sec
3117
+ latitude: CoordinateUtils.getDirection(msg.substring(12, 13)) * (Number(msg.substring(13, 15)) + Number(msg.substring(15, 17)) / 60),
3118
+ longitude: CoordinateUtils.getDirection(msg.substring(17, 18)) * (Number(msg.substring(18, 21)) + Number(msg.substring(21, 23)) / 60)
3119
+ });
3120
+ ResultFormatter.altitude(decodeResult, Number(msg.substring(23, 28)));
3121
+ ResultFormatter.unknown(decodeResult, msg.substring(28));
3122
+ decodeResult.decoded = true;
3123
+ decodeResult.decoder.decodeLevel = "partial";
3124
+ return decodeResult;
3125
+ }
3126
+ };
3127
+
3128
+ // lib/plugins/Label_H1_WRN.ts
3129
+ var Label_H1_WRN = class extends DecoderPlugin {
3130
+ name = "label-h1-wrn";
3131
+ qualifiers() {
3132
+ return {
3133
+ labels: ["H1"],
3134
+ preambles: ["WRN", "#CFBWRN"]
3135
+ };
3136
+ }
3137
+ decode(message, options = {}) {
3138
+ let decodeResult = this.defaultResult();
3139
+ decodeResult.decoder.name = this.name;
3140
+ decodeResult.formatted.description = "Warning Message";
3141
+ decodeResult.message = message;
3142
+ const parts = message.text.split("/WN");
3143
+ if (parts.length > 1) {
3144
+ const fields = parts[0].split("/");
3145
+ ResultFormatter.unknownArr(decodeResult, fields.slice(1), "/");
3146
+ const data = parts[1].substring(0, 20);
3147
+ const msg = parts[1].substring(20);
3148
+ const datetime = data.substring(0, 12);
3149
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
3150
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
3151
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
3152
+ decodeResult.raw.warning_message = msg;
3153
+ decodeResult.formatted.items.push({
3154
+ type: "warning",
3155
+ code: "WRN",
3156
+ label: "Warning Message",
3157
+ value: decodeResult.raw.warning_message
3158
+ });
3159
+ decodeResult.decoded = true;
3160
+ decodeResult.decoder.decodeLevel = "partial";
3161
+ } else {
3162
+ if (options.debug) {
3163
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
3164
+ }
3165
+ ResultFormatter.unknown(decodeResult, message.text);
2855
3166
  decodeResult.decoded = false;
2856
3167
  decodeResult.decoder.decodeLevel = "none";
2857
3168
  }
@@ -2882,25 +3193,18 @@ var Label_HX = class extends DecoderPlugin {
2882
3193
  let londir = parts[4].substring(0, 1);
2883
3194
  let londeg = Number(parts[4].substring(1, 4));
2884
3195
  let lonmin = Number(parts[4].substring(4, 8));
2885
- decodeResult.raw.position = {
3196
+ let pos = {
2886
3197
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2887
3198
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2888
3199
  };
2889
- decodeResult.remaining.text = parts.slice(5).join(" ");
3200
+ ResultFormatter.unknownArr(decodeResult, parts.slice(5), " ");
3201
+ ResultFormatter.position(decodeResult, pos);
2890
3202
  } else if (parts[2] === "43") {
2891
3203
  ResultFormatter.departureAirport(decodeResult, parts[3]);
2892
- decodeResult.remaining.text = parts.slice(4).join(" ");
3204
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), " ");
2893
3205
  } else {
2894
3206
  decodeResult.decoded = false;
2895
3207
  }
2896
- if (decodeResult.raw.position) {
2897
- decodeResult.formatted.items.push({
2898
- type: "aircraft_position",
2899
- code: "POS",
2900
- label: "Aircraft Position",
2901
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2902
- });
2903
- }
2904
3208
  if (decodeResult.decoded) {
2905
3209
  if (!decodeResult.remaining.text)
2906
3210
  decodeResult.decoder.decodeLevel = "full";
@@ -2930,7 +3234,7 @@ var Label_SQ = class extends DecoderPlugin {
2930
3234
  if (decodeResult.raw.version === "2") {
2931
3235
  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+)\/.*/;
2932
3236
  const result = message.text.match(regex);
2933
- if (result && result.length >= 8) {
3237
+ if (result?.groups && result.length >= 8) {
2934
3238
  decodeResult.raw.groundStation = {
2935
3239
  number: result.groups.station,
2936
3240
  iataCode: result.groups.iata,
@@ -2940,7 +3244,7 @@ var Label_SQ = class extends DecoderPlugin {
2940
3244
  longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
2941
3245
  }
2942
3246
  };
2943
- decodeResult.raw.vdlFrequency = result.groups.vfreq / 1e3;
3247
+ decodeResult.raw.vdlFrequency = Number(result.groups.vfreq) / 1e3;
2944
3248
  }
2945
3249
  }
2946
3250
  decodeResult.formatted.description = "Ground Station Squitter";
@@ -3031,31 +3335,11 @@ var Label_QR = class extends DecoderPlugin {
3031
3335
  decode(message, options = {}) {
3032
3336
  const decodeResult = this.defaultResult();
3033
3337
  decodeResult.decoder.name = this.name;
3034
- decodeResult.raw.origin = message.text.substring(0, 4);
3035
- decodeResult.raw.destination = message.text.substring(4, 8);
3036
- decodeResult.raw.wheels_on = message.text.substring(8, 12);
3037
- decodeResult.remaining.text = message.text.substring(12);
3038
3338
  decodeResult.formatted.description = "ON Report";
3039
- decodeResult.formatted.items = [
3040
- {
3041
- type: "origin",
3042
- code: "ORG",
3043
- label: "Origin",
3044
- value: decodeResult.raw.origin
3045
- },
3046
- {
3047
- type: "destination",
3048
- code: "DST",
3049
- label: "Destination",
3050
- value: decodeResult.raw.destination
3051
- },
3052
- {
3053
- type: "wheels_on",
3054
- code: "WON",
3055
- label: "Wheels ON",
3056
- value: decodeResult.raw.wheels_on
3057
- }
3058
- ];
3339
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3340
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3341
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3342
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3059
3343
  decodeResult.decoded = true;
3060
3344
  if (!decodeResult.remaining.text)
3061
3345
  decodeResult.decoder.decodeLevel = "full";
@@ -3076,31 +3360,11 @@ var Label_QP = class extends DecoderPlugin {
3076
3360
  decode(message, options = {}) {
3077
3361
  const decodeResult = this.defaultResult();
3078
3362
  decodeResult.decoder.name = this.name;
3079
- decodeResult.raw.origin = message.text.substring(0, 4);
3080
- decodeResult.raw.destination = message.text.substring(4, 8);
3081
- decodeResult.raw.gate_out = message.text.substring(8, 12);
3082
- decodeResult.remaining.text = message.text.substring(12);
3083
3363
  decodeResult.formatted.description = "OUT Report";
3084
- decodeResult.formatted.items = [
3085
- {
3086
- type: "origin",
3087
- code: "ORG",
3088
- label: "Origin",
3089
- value: decodeResult.raw.origin
3090
- },
3091
- {
3092
- type: "destination",
3093
- code: "DST",
3094
- label: "Destination",
3095
- value: decodeResult.raw.destination
3096
- },
3097
- {
3098
- type: "gate_out",
3099
- code: "GOUT",
3100
- label: "Gate OUT",
3101
- value: decodeResult.raw.gate_out
3102
- }
3103
- ];
3364
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3365
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3366
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3367
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3104
3368
  decodeResult.decoded = true;
3105
3369
  if (!decodeResult.remaining.text)
3106
3370
  decodeResult.decoder.decodeLevel = "full";
@@ -3121,31 +3385,11 @@ var Label_QS = class extends DecoderPlugin {
3121
3385
  decode(message, options = {}) {
3122
3386
  const decodeResult = this.defaultResult();
3123
3387
  decodeResult.decoder.name = this.name;
3124
- decodeResult.raw.origin = message.text.substring(0, 4);
3125
- decodeResult.raw.destination = message.text.substring(4, 8);
3126
- decodeResult.raw.gate_in = message.text.substring(8, 12);
3127
- decodeResult.remaining.text = message.text.substring(12);
3128
3388
  decodeResult.formatted.description = "IN Report";
3129
- decodeResult.formatted.items = [
3130
- {
3131
- type: "origin",
3132
- code: "ORG",
3133
- label: "Origin",
3134
- value: decodeResult.raw.origin
3135
- },
3136
- {
3137
- type: "destination",
3138
- code: "DST",
3139
- label: "Destination",
3140
- value: decodeResult.raw.destination
3141
- },
3142
- {
3143
- type: "gate_in",
3144
- code: "GIN",
3145
- label: "Gate IN",
3146
- value: decodeResult.raw.gate_in
3147
- }
3148
- ];
3389
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3390
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3391
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3392
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3149
3393
  decodeResult.decoded = true;
3150
3394
  if (!decodeResult.remaining.text)
3151
3395
  decodeResult.decoder.decodeLevel = "full";
@@ -3170,43 +3414,30 @@ var Label_QQ = class extends DecoderPlugin {
3170
3414
  decodeResult.formatted.description = "OFF Report";
3171
3415
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3172
3416
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3173
- decodeResult.raw.wheels_off = message.text.substring(8, 12);
3174
3417
  if (message.text.substring(12, 19) === "\r\n001FE") {
3175
3418
  decodeResult.raw.day_of_month = message.text.substring(19, 21);
3176
- decodeResult.raw.wheels_off = message.text.substring(21, 27);
3419
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
3177
3420
  let latdir = message.text.substring(27, 28);
3178
3421
  let latdeg = Number(message.text.substring(28, 30));
3179
3422
  let latmin = Number(message.text.substring(30, 34));
3180
3423
  let londir = message.text.substring(34, 35);
3181
3424
  let londeg = Number(message.text.substring(35, 38));
3182
3425
  let lonmin = Number(message.text.substring(38, 42));
3183
- decodeResult.raw.position = {
3426
+ let pos = {
3184
3427
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
3185
3428
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
3186
3429
  };
3187
- decodeResult.remaining.text = message.text.substring(42, 45);
3430
+ ResultFormatter.unknown(decodeResult, message.text.substring(42, 45));
3431
+ ResultFormatter.position(decodeResult, pos);
3188
3432
  if (decodeResult.remaining.text !== "---") {
3189
- ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
3433
+ ResultFormatter.groundspeed(decodeResult, Number(message.text.substring(45, 48)));
3190
3434
  } else {
3191
3435
  ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
3192
3436
  }
3193
3437
  ResultFormatter.unknown(decodeResult, message.text.substring(48));
3194
3438
  } else {
3195
- decodeResult.remaining.text = message.text.substring(12);
3196
- }
3197
- decodeResult.formatted.items.push({
3198
- type: "wheels_off",
3199
- code: "WOFF",
3200
- label: "Wheels OFF",
3201
- value: decodeResult.raw.wheels_off
3202
- });
3203
- if (decodeResult.raw.position) {
3204
- decodeResult.formatted.items.push({
3205
- type: "aircraft_position",
3206
- code: "POS",
3207
- label: "Aircraft Position",
3208
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
3209
- });
3439
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3440
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3210
3441
  }
3211
3442
  decodeResult.decoded = true;
3212
3443
  if (!decodeResult.remaining.text)
@@ -4038,8 +4269,14 @@ var MessageDecoder = class {
4038
4269
  this.registerPlugin(new Label_15(this));
4039
4270
  this.registerPlugin(new Label_15_FST(this));
4040
4271
  this.registerPlugin(new Label_16_N_Space(this));
4272
+ this.registerPlugin(new Label_1L_3Line(this));
4273
+ this.registerPlugin(new Label_1L_070(this));
4274
+ this.registerPlugin(new Label_1L_660(this));
4275
+ this.registerPlugin(new Label_1L_Slash(this));
4041
4276
  this.registerPlugin(new Label_20_POS(this));
4042
4277
  this.registerPlugin(new Label_21_POS(this));
4278
+ this.registerPlugin(new Label_22_OFF(this));
4279
+ this.registerPlugin(new Label_22_POS(this));
4043
4280
  this.registerPlugin(new Label_24_Slash(this));
4044
4281
  this.registerPlugin(new Label_30_Slash_EA(this));
4045
4282
  this.registerPlugin(new Label_44_ETA(this));
@@ -4052,12 +4289,14 @@ var MessageDecoder = class {
4052
4289
  this.registerPlugin(new Label_4A_DIS(this));
4053
4290
  this.registerPlugin(new Label_4A_DOOR(this));
4054
4291
  this.registerPlugin(new Label_4A_Slash_01(this));
4292
+ this.registerPlugin(new Label_4J_POS(this));
4055
4293
  this.registerPlugin(new Label_4N(this));
4056
4294
  this.registerPlugin(new Label_B6_Forwardslash(this));
4057
4295
  this.registerPlugin(new Label_H1_FLR(this));
4058
4296
  this.registerPlugin(new Label_H1_OHMA(this));
4059
4297
  this.registerPlugin(new Label_H1_WRN(this));
4060
4298
  this.registerPlugin(new Label_H1(this));
4299
+ this.registerPlugin(new Label_H1_StarPOS(this));
4061
4300
  this.registerPlugin(new Label_HX(this));
4062
4301
  this.registerPlugin(new Label_80(this));
4063
4302
  this.registerPlugin(new Label_83(this));