@airframes/acars-decoder 1.8.7 → 1.8.8

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
@@ -627,8 +627,11 @@ var ResultFormatter = class {
627
627
  value: decodeResult.raw.fuel_remaining.toString()
628
628
  });
629
629
  }
630
+ static checksumAlgorithm(decodeResult, value) {
631
+ decodeResult.raw.checksum_algorithm = value;
632
+ }
630
633
  static checksum(decodeResult, value) {
631
- decodeResult.raw.checksum = Number("0x" + value);
634
+ decodeResult.raw.checksum = value;
632
635
  decodeResult.formatted.items.push({
633
636
  type: "message_checksum",
634
637
  code: "CHECKSUM",
@@ -2012,9 +2015,14 @@ function addCompanyRoute(decodeResult, value) {
2012
2015
  // lib/utils/h1_helper.ts
2013
2016
  var H1Helper = class _H1Helper {
2014
2017
  static decodeH1Message(decodeResult, message) {
2015
- const checksum = message.slice(-4);
2018
+ const checksum = parseInt(message.slice(-4), 16);
2016
2019
  const data = message.slice(0, message.length - 4);
2017
- if (calculateChecksum(data) !== checksum) {
2020
+ let checksumAlgorithmUsed = "";
2021
+ if (crc16IbmSdlcRev(data) === checksum) {
2022
+ checksumAlgorithmUsed = "IBM-SDLC reversed";
2023
+ } else if (crc16Genibus(data) === checksum) {
2024
+ checksumAlgorithmUsed = "GENIBUS";
2025
+ } else {
2018
2026
  decodeResult.decoded = false;
2019
2027
  decodeResult.decoder.decodeLevel = "none";
2020
2028
  return false;
@@ -2091,6 +2099,9 @@ var H1Helper = class _H1Helper {
2091
2099
  case "RN":
2092
2100
  ResultFormatter.routeNumber(decodeResult, data2);
2093
2101
  break;
2102
+ case "RW":
2103
+ processRunway(decodeResult, data2.split(":"));
2104
+ break;
2094
2105
  case "SN":
2095
2106
  decodeResult.raw.serial_number = data2;
2096
2107
  break;
@@ -2116,6 +2127,7 @@ var H1Helper = class _H1Helper {
2116
2127
  ResultFormatter.unknown(decodeResult, fields[i], "/");
2117
2128
  }
2118
2129
  }
2130
+ ResultFormatter.checksumAlgorithm(decodeResult, checksumAlgorithmUsed);
2119
2131
  ResultFormatter.checksum(decodeResult, checksum);
2120
2132
  return true;
2121
2133
  }
@@ -2230,29 +2242,42 @@ function processIdentification(decodeResult, data) {
2230
2242
  }
2231
2243
  }
2232
2244
  function processDT(decodeResult, data) {
2233
- if (!decodeResult.raw.arrival_icao) {
2234
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2235
- } else if (decodeResult.raw.arrival_icao != data[0]) {
2236
- ResultFormatter.unknownArr(decodeResult, data);
2245
+ if (data.length === 9) {
2246
+ ResultFormatter.unknown(decodeResult, data[0]);
2247
+ if (!decodeResult.raw.arrival_icao) {
2248
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
2249
+ }
2250
+ ResultFormatter.arrivalRunway(decodeResult, data[2]);
2251
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[3], 10));
2252
+ ResultFormatter.eta(
2253
+ decodeResult,
2254
+ DateTimeUtils.convertHHMMSSToTod(data[4])
2255
+ );
2256
+ ResultFormatter.unknown(decodeResult, data[5]);
2257
+ ResultFormatter.position(
2258
+ decodeResult,
2259
+ CoordinateUtils.decodeStringCoordinates(data[6])
2260
+ );
2261
+ ResultFormatter.unknown(decodeResult, data[7]);
2262
+ ResultFormatter.unknown(decodeResult, data[8]);
2263
+ return;
2237
2264
  }
2238
- if (data.length > 1) {
2265
+ if (data.length === 4 || data.length === 5) {
2266
+ if (!decodeResult.raw.arrival_icao) {
2267
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
2268
+ }
2239
2269
  ResultFormatter.arrivalRunway(decodeResult, data[1]);
2240
- }
2241
- if (data.length > 2) {
2242
- ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2243
- }
2244
- if (data.length > 3) {
2270
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
2245
2271
  ResultFormatter.eta(
2246
2272
  decodeResult,
2247
2273
  DateTimeUtils.convertHHMMSSToTod(data[3])
2248
2274
  );
2275
+ if (data.length > 4) {
2276
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2277
+ }
2278
+ return;
2249
2279
  }
2250
- if (data.length > 4) {
2251
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2252
- }
2253
- if (data.length > 5) {
2254
- ResultFormatter.unknownArr(decodeResult, data);
2255
- }
2280
+ ResultFormatter.unknownArr(decodeResult, data, ",");
2256
2281
  }
2257
2282
  function processLandingReport(decodeResult, data) {
2258
2283
  if (data.length === 19) {
@@ -2316,7 +2341,9 @@ function processMessageType(decodeResult, type) {
2316
2341
  } else if (type === "FTX") {
2317
2342
  decodeResult.formatted.description = "Free Text";
2318
2343
  } else if (type === "INI") {
2319
- decodeResult.formatted.description = "Flight Plan Initial Report";
2344
+ decodeResult.formatted.description = "Initial Report";
2345
+ } else if (type === "LDI") {
2346
+ decodeResult.formatted.description = "Load Distribution Information";
2320
2347
  } else if (type === "PER") {
2321
2348
  decodeResult.formatted.description = "Performance Report";
2322
2349
  } else if (type === "POS") {
@@ -2381,11 +2408,14 @@ function processWindData(decodeResult, message) {
2381
2408
  const flightLevel = Number(message.slice(0, 3));
2382
2409
  const fields = message.slice(4).split(".");
2383
2410
  fields.forEach((field) => {
2411
+ if (field.length < 4) {
2412
+ return;
2413
+ }
2384
2414
  const data = field.split(",");
2385
2415
  const waypoint = { name: data[0] };
2386
2416
  const windData = data[1];
2387
- const windDirection = Number(windData.slice(0, 3));
2388
- const windSpeed = Number(windData.slice(3));
2417
+ const windDirection = parseInt(windData.slice(0, 3), 10);
2418
+ const windSpeed = parseInt(windData.slice(3), 10);
2389
2419
  if (data.length === 3) {
2390
2420
  const tempData = data[2];
2391
2421
  const tempFlightLevel = Number(tempData.slice(0, 3));
@@ -2412,7 +2442,16 @@ function processWindData(decodeResult, message) {
2412
2442
  });
2413
2443
  ResultFormatter.windData(decodeResult, wind);
2414
2444
  }
2415
- function calculateChecksum(data) {
2445
+ function processRunway(decodeResult, data) {
2446
+ const parts = data[0].split(".");
2447
+ const more = parts[0].split(",");
2448
+ ResultFormatter.departureRunway(decodeResult, more[0]);
2449
+ ResultFormatter.unknownArr(decodeResult, more.slice(1), ",");
2450
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), ".");
2451
+ ResultFormatter.departureAirport(decodeResult, data[1].split(",")[0]);
2452
+ ResultFormatter.unknownArr(decodeResult, data[1].split(",").slice(1), ",");
2453
+ }
2454
+ function crc16IbmSdlcRev(data) {
2416
2455
  let crc = 65535;
2417
2456
  const bytes = Buffer.from(data, "ascii");
2418
2457
  for (const byte of bytes) {
@@ -2430,7 +2469,23 @@ function calculateChecksum(data) {
2430
2469
  const nibble2 = crc >> 8 & 15;
2431
2470
  const nibble3 = crc >> 4 & 15;
2432
2471
  const nibble4 = crc & 15;
2433
- return `${nibble4.toString(16)}${nibble3.toString(16)}${nibble2.toString(16)}${nibble1.toString(16)}`.toUpperCase();
2472
+ return nibble4 << 12 | nibble3 << 8 | nibble2 << 4 | nibble1;
2473
+ }
2474
+ function crc16Genibus(data) {
2475
+ let crc = 65535;
2476
+ const polynomial = 4129;
2477
+ const bytes = Buffer.from(data, "ascii");
2478
+ for (const byte of bytes) {
2479
+ crc ^= byte << 8;
2480
+ for (let i = 0; i < 8; i++) {
2481
+ if ((crc & 32768) !== 0) {
2482
+ crc = (crc << 1 ^ polynomial) & 65535;
2483
+ } else {
2484
+ crc = crc << 1 & 65535;
2485
+ }
2486
+ }
2487
+ }
2488
+ return (crc ^ 65535) & 65535;
2434
2489
  }
2435
2490
 
2436
2491
  // lib/plugins/Label_1J_2J_FTX.ts
@@ -4029,7 +4084,7 @@ var Label_4N = class extends DecoderPlugin {
4029
4084
  if (fields[12].length > 1) {
4030
4085
  ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
4031
4086
  }
4032
- ResultFormatter.checksum(decodeResult, fields[32]);
4087
+ ResultFormatter.checksum(decodeResult, parseInt(fields[32], 16));
4033
4088
  ResultFormatter.unknownArr(
4034
4089
  decodeResult,
4035
4090
  [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter(
@@ -4538,7 +4593,7 @@ var Label_H1 = class extends DecoderPlugin {
4538
4593
  } else if (parts.length === 1) {
4539
4594
  decoded = H1Helper.decodeH1Message(decodeResult, msg);
4540
4595
  } else if (parts.length == 2) {
4541
- const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
4596
+ const offset = parts[0] === "- " || isNaN(parseInt(parts[1][1])) ? 3 : 4;
4542
4597
  decoded = H1Helper.decodeH1Message(
4543
4598
  decodeResult,
4544
4599
  msg.slice(parts[0].length + offset)
@@ -4759,6 +4814,66 @@ var Label_H1_OHMA = class extends DecoderPlugin {
4759
4814
  }
4760
4815
  };
4761
4816
 
4817
+ // lib/plugins/Label_H1_Paren.ts
4818
+ var Label_H1_Paren = class extends DecoderPlugin {
4819
+ name = "label-h1-paren";
4820
+ qualifiers() {
4821
+ return {
4822
+ labels: ["H1"],
4823
+ preambles: ["("]
4824
+ };
4825
+ }
4826
+ decode(message) {
4827
+ let decodeResult = this.defaultResult();
4828
+ decodeResult.decoder.name = this.name;
4829
+ decodeResult.message = message;
4830
+ if (!message.text || !message.text.startsWith("(")) {
4831
+ decodeResult.decoded = false;
4832
+ return decodeResult;
4833
+ }
4834
+ const regex = /^\(POS-(?<flight>\w+)\s+(?<lat>-?\d{4,5}[NS])(?<lon>\d{5}[EW])\/(?<timestamp>\d{6})\s+F(?<alt>\d{3})\r?\nRMK\/FUEL\s+(?<fuel>\d{2,3}\.\d)\s+M(?<mach>\d\.\d{2})\)/;
4835
+ const match = message.text.match(regex);
4836
+ if (match && match.groups) {
4837
+ decodeResult.decoded = true;
4838
+ decodeResult.decoder.decodeLevel = "partial";
4839
+ decodeResult.formatted.description = "Position Report";
4840
+ ResultFormatter.flightNumber(decodeResult, match.groups.flight);
4841
+ ResultFormatter.position(decodeResult, {
4842
+ latitude: parseLat(match.groups.lat),
4843
+ longitude: parseLon(match.groups.lon)
4844
+ });
4845
+ ResultFormatter.time_of_day(
4846
+ decodeResult,
4847
+ DateTimeUtils.convertHHMMSSToTod(match.groups.timestamp)
4848
+ );
4849
+ ResultFormatter.altitude(
4850
+ decodeResult,
4851
+ parseInt(match.groups.alt, 10) * 100
4852
+ );
4853
+ ResultFormatter.currentFuel(decodeResult, parseFloat(match.groups.fuel));
4854
+ ResultFormatter.mach(decodeResult, parseFloat(match.groups.mach));
4855
+ ResultFormatter.unknown(decodeResult, "RMK");
4856
+ }
4857
+ return decodeResult;
4858
+ }
4859
+ };
4860
+ function parseLat(latStr) {
4861
+ const match = latStr.match(/(-?)(\d{2})(\d{2})([NS])/);
4862
+ if (!match) return NaN;
4863
+ let deg = parseInt(match[2]);
4864
+ let min = parseInt(match[3]);
4865
+ let sign = match[4] === "S" ? -1 : 1;
4866
+ return sign * (deg + min / 60);
4867
+ }
4868
+ function parseLon(lonStr) {
4869
+ const match = lonStr.match(/(\d{3})(\d{2})([EW])/);
4870
+ if (!match) return NaN;
4871
+ let deg = parseInt(match[1]);
4872
+ let min = parseInt(match[2]);
4873
+ let sign = match[3] === "W" ? -1 : 1;
4874
+ return sign * (deg + min / 60);
4875
+ }
4876
+
4762
4877
  // lib/plugins/Label_H1_StarPOS.ts
4763
4878
  var Label_H1_StarPOS = class extends DecoderPlugin {
4764
4879
  name = "label-h1-star-pos";
@@ -6154,6 +6269,7 @@ var MessageDecoder = class {
6154
6269
  this.registerPlugin(new Label_H2_02E(this));
6155
6270
  this.registerPlugin(new Label_H1_FLR(this));
6156
6271
  this.registerPlugin(new Label_H1_OHMA(this));
6272
+ this.registerPlugin(new Label_H1_Paren(this));
6157
6273
  this.registerPlugin(new Label_H1_WRN(this));
6158
6274
  this.registerPlugin(new Label_H1(this));
6159
6275
  this.registerPlugin(new Label_H1_StarPOS(this));