@airframes/acars-decoder 1.6.9 → 1.6.11
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 +926 -459
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +926 -459
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -97,6 +97,271 @@ var DecoderPlugin = class {
|
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
+
// lib/utils/coordinate_utils.ts
|
|
101
|
+
var CoordinateUtils = class {
|
|
102
|
+
/**
|
|
103
|
+
* Decode a string of coordinates into an object with latitude and longitude in millidegrees
|
|
104
|
+
* @param stringCoords - The string of coordinates to decode
|
|
105
|
+
*
|
|
106
|
+
* @returns An object with latitude and longitude properties
|
|
107
|
+
*/
|
|
108
|
+
static decodeStringCoordinates(stringCoords) {
|
|
109
|
+
var results = {};
|
|
110
|
+
const firstChar = stringCoords.substring(0, 1);
|
|
111
|
+
let middleChar = stringCoords.substring(6, 7);
|
|
112
|
+
let longitudeChars = stringCoords.substring(7, 13);
|
|
113
|
+
if (middleChar == " ") {
|
|
114
|
+
middleChar = stringCoords.substring(7, 8);
|
|
115
|
+
longitudeChars = stringCoords.substring(8, 14);
|
|
116
|
+
}
|
|
117
|
+
if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
|
|
118
|
+
results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
|
|
119
|
+
results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
|
|
120
|
+
} else {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
return results;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
|
|
127
|
+
* @param stringCoords - The string of coordinates to decode
|
|
128
|
+
*
|
|
129
|
+
* @returns An object with latitude and longitude properties
|
|
130
|
+
*/
|
|
131
|
+
static decodeStringCoordinatesDecimalMinutes(stringCoords) {
|
|
132
|
+
var results = {};
|
|
133
|
+
const firstChar = stringCoords.substring(0, 1);
|
|
134
|
+
let middleChar = stringCoords.substring(6, 7);
|
|
135
|
+
let longitudeChars = stringCoords.substring(7, 13);
|
|
136
|
+
if (middleChar == " ") {
|
|
137
|
+
middleChar = stringCoords.substring(7, 8);
|
|
138
|
+
longitudeChars = stringCoords.substring(8, 14);
|
|
139
|
+
}
|
|
140
|
+
const latDeg = Math.trunc(Number(stringCoords.substring(1, 6)) / 1e3);
|
|
141
|
+
const latMin = Number(stringCoords.substring(1, 6)) % 1e3 / 10;
|
|
142
|
+
const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
|
|
143
|
+
const lonMin = Number(longitudeChars) % 1e3 / 10;
|
|
144
|
+
if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
|
|
145
|
+
results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
|
|
146
|
+
results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
|
|
147
|
+
} else {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
return results;
|
|
151
|
+
}
|
|
152
|
+
static coordinateString(coords) {
|
|
153
|
+
const latDir = coords.latitude > 0 ? "N" : "S";
|
|
154
|
+
const lonDir = coords.longitude > 0 ? "E" : "W";
|
|
155
|
+
return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
|
|
156
|
+
}
|
|
157
|
+
static getDirection(coord) {
|
|
158
|
+
if (coord.startsWith("N") || coord.startsWith("E")) {
|
|
159
|
+
return 1;
|
|
160
|
+
} else if (coord.startsWith("S") || coord.startsWith("W")) {
|
|
161
|
+
return -1;
|
|
162
|
+
}
|
|
163
|
+
return NaN;
|
|
164
|
+
}
|
|
165
|
+
static dmsToDecimalDegrees(degrees, minutes, seconds) {
|
|
166
|
+
return degrees + minutes / 60 + seconds / 3600;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// lib/utils/result_formatter.ts
|
|
171
|
+
var ResultFormatter = class {
|
|
172
|
+
static position(decodeResult, value) {
|
|
173
|
+
decodeResult.raw.position = value;
|
|
174
|
+
decodeResult.formatted.items.push({
|
|
175
|
+
type: "aircraft_position",
|
|
176
|
+
code: "POS",
|
|
177
|
+
label: "Aircraft Position",
|
|
178
|
+
value: CoordinateUtils.coordinateString(value)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
static altitude(decodeResult, value) {
|
|
182
|
+
decodeResult.raw.altitude = value;
|
|
183
|
+
decodeResult.formatted.items.push({
|
|
184
|
+
type: "altitude",
|
|
185
|
+
code: "ALT",
|
|
186
|
+
label: "Altitude",
|
|
187
|
+
value: `${decodeResult.raw.altitude} feet`
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
static flightNumber(decodeResult, value) {
|
|
191
|
+
decodeResult.raw.flight_number = value;
|
|
192
|
+
}
|
|
193
|
+
static departureAirport(decodeResult, value) {
|
|
194
|
+
decodeResult.raw.departure_icao = value;
|
|
195
|
+
decodeResult.formatted.items.push({
|
|
196
|
+
type: "origin",
|
|
197
|
+
code: "ORG",
|
|
198
|
+
label: "Origin",
|
|
199
|
+
value: decodeResult.raw.departure_icao
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
static departureRunway(decodeResult, value) {
|
|
203
|
+
decodeResult.raw.departure_runway = value;
|
|
204
|
+
decodeResult.formatted.items.push({
|
|
205
|
+
type: "runway",
|
|
206
|
+
code: "DEPRWY",
|
|
207
|
+
label: "Departure Runway",
|
|
208
|
+
value: decodeResult.raw.departure_runway
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
static arrivalAirport(decodeResult, value) {
|
|
212
|
+
decodeResult.raw.arrival_icao = value;
|
|
213
|
+
decodeResult.formatted.items.push({
|
|
214
|
+
type: "destination",
|
|
215
|
+
code: "DST",
|
|
216
|
+
label: "Destination",
|
|
217
|
+
value: decodeResult.raw.arrival_icao
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
static alternateAirport(decodeResult, value) {
|
|
221
|
+
decodeResult.raw.alternate_icao = value;
|
|
222
|
+
decodeResult.formatted.items.push({
|
|
223
|
+
type: "destination",
|
|
224
|
+
code: "ALT_DST",
|
|
225
|
+
label: "Alternate Destination",
|
|
226
|
+
value: decodeResult.raw.alternate_icao
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
// FIXME - make seconds since midnight for time of day
|
|
230
|
+
static eta(decodeResult, value) {
|
|
231
|
+
decodeResult.raw.eta_time = value;
|
|
232
|
+
decodeResult.formatted.items.push({
|
|
233
|
+
type: "eta",
|
|
234
|
+
code: "ETA",
|
|
235
|
+
label: "Estimated Time of Arrival",
|
|
236
|
+
value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
static arrivalRunway(decodeResult, value) {
|
|
240
|
+
decodeResult.raw.arrival_runway = value;
|
|
241
|
+
decodeResult.formatted.items.push({
|
|
242
|
+
type: "runway",
|
|
243
|
+
code: "ARWY",
|
|
244
|
+
label: "Arrival Runway",
|
|
245
|
+
value: decodeResult.raw.arrival_runway
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
static alternateRunway(decodeResult, value) {
|
|
249
|
+
decodeResult.raw.alternate_runway = value;
|
|
250
|
+
decodeResult.formatted.items.push({
|
|
251
|
+
type: "runway",
|
|
252
|
+
code: "ALT_ARWY",
|
|
253
|
+
label: "Alternate Runway",
|
|
254
|
+
value: decodeResult.raw.alternate_runway
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
static currentFuel(decodeResult, value) {
|
|
258
|
+
decodeResult.raw.fuel_on_board = value;
|
|
259
|
+
decodeResult.formatted.items.push({
|
|
260
|
+
type: "fuel_on_board",
|
|
261
|
+
code: "FOB",
|
|
262
|
+
label: "Fuel On Board",
|
|
263
|
+
value: decodeResult.raw.fuel_on_board.toString()
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
static remainingFuel(decodeResult, value) {
|
|
267
|
+
decodeResult.raw.fuel_remaining = value;
|
|
268
|
+
decodeResult.formatted.items.push({
|
|
269
|
+
type: "fuel_remaining",
|
|
270
|
+
code: "FUEL",
|
|
271
|
+
label: "Fuel Remaining",
|
|
272
|
+
value: decodeResult.raw.fuel_remaining.toString()
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
static checksum(decodeResult, value) {
|
|
276
|
+
decodeResult.raw.checksum = Number("0x" + value);
|
|
277
|
+
decodeResult.formatted.items.push({
|
|
278
|
+
type: "message_checksum",
|
|
279
|
+
code: "CHECKSUM",
|
|
280
|
+
label: "Message Checksum",
|
|
281
|
+
value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
static groundspeed(decodeResult, value) {
|
|
285
|
+
decodeResult.raw.groundspeed = value;
|
|
286
|
+
decodeResult.formatted.items.push({
|
|
287
|
+
type: "aircraft_groundspeed",
|
|
288
|
+
code: "GSPD",
|
|
289
|
+
label: "Aircraft Groundspeed",
|
|
290
|
+
value: `${decodeResult.raw.groundspeed} knots`
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
static temperature(decodeResult, value) {
|
|
294
|
+
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
295
|
+
decodeResult.formatted.items.push({
|
|
296
|
+
type: "outside_air_temperature",
|
|
297
|
+
code: "OATEMP",
|
|
298
|
+
label: "Outside Air Temperature (C)",
|
|
299
|
+
value: `${decodeResult.raw.outside_air_temperature}`
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
static heading(decodeResult, value) {
|
|
303
|
+
decodeResult.raw.heading = value;
|
|
304
|
+
decodeResult.formatted.items.push({
|
|
305
|
+
type: "heading",
|
|
306
|
+
code: "HDG",
|
|
307
|
+
label: "Heading",
|
|
308
|
+
value: `${decodeResult.raw.heading}`
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
static tail(decodeResult, value) {
|
|
312
|
+
decodeResult.raw.tail = value;
|
|
313
|
+
decodeResult.formatted.items.push({
|
|
314
|
+
type: "tail",
|
|
315
|
+
code: "TAIL",
|
|
316
|
+
label: "Tail",
|
|
317
|
+
value: decodeResult.raw.tail
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
static out(decodeResult, time) {
|
|
321
|
+
decodeResult.raw.out_time = time;
|
|
322
|
+
const date = new Date(time * 1e3);
|
|
323
|
+
decodeResult.formatted.items.push({
|
|
324
|
+
type: "time_of_day",
|
|
325
|
+
code: "OUT",
|
|
326
|
+
label: "Out of Gate Time",
|
|
327
|
+
value: date.toISOString().slice(11, 19)
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
static off(decodeResult, time) {
|
|
331
|
+
decodeResult.raw.off_time = time;
|
|
332
|
+
const date = new Date(time * 1e3);
|
|
333
|
+
decodeResult.formatted.items.push({
|
|
334
|
+
type: "time_of_day",
|
|
335
|
+
code: "OFF",
|
|
336
|
+
label: "Takeoff Time",
|
|
337
|
+
value: date.toISOString().slice(11, 19)
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
static on(decodeResult, time) {
|
|
341
|
+
decodeResult.raw.on_time = time;
|
|
342
|
+
const date = new Date(time * 1e3);
|
|
343
|
+
decodeResult.formatted.items.push({
|
|
344
|
+
type: "time_of_day",
|
|
345
|
+
code: "ON",
|
|
346
|
+
label: "Landing Time",
|
|
347
|
+
value: date.toISOString().slice(11, 19)
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
static in(decodeResult, time) {
|
|
351
|
+
decodeResult.raw.in_time = time;
|
|
352
|
+
const date = new Date(time * 1e3);
|
|
353
|
+
decodeResult.formatted.items.push({
|
|
354
|
+
type: "time_of_day",
|
|
355
|
+
code: "IN",
|
|
356
|
+
label: "In Gate Time",
|
|
357
|
+
value: date.toISOString().slice(11, 19)
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
static unknown(decodeResult, value) {
|
|
361
|
+
decodeResult.remaining.text += "," + value;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
100
365
|
// lib/plugins/Label_5Z.ts
|
|
101
366
|
var Label_5Z = class extends DecoderPlugin {
|
|
102
367
|
name = "label-5z";
|
|
@@ -156,34 +421,9 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
156
421
|
const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
|
|
157
422
|
results = remainder.match(rdcRegex);
|
|
158
423
|
if (results) {
|
|
159
|
-
decodeResult
|
|
160
|
-
decodeResult.
|
|
161
|
-
|
|
162
|
-
label: "Origin",
|
|
163
|
-
value: `${results.groups.from}`
|
|
164
|
-
});
|
|
165
|
-
decodeResult.raw.destination = results.groups.to;
|
|
166
|
-
decodeResult.formatted.items.push({
|
|
167
|
-
type: "destination",
|
|
168
|
-
label: "Destination",
|
|
169
|
-
value: `${results.groups.to}`
|
|
170
|
-
});
|
|
171
|
-
decodeResult.formatted.items.push({
|
|
172
|
-
type: "unknown1",
|
|
173
|
-
label: "Unknown Field 1",
|
|
174
|
-
value: `${results.groups.unknown1}`
|
|
175
|
-
});
|
|
176
|
-
decodeResult.raw.runway = results.groups.runway;
|
|
177
|
-
decodeResult.formatted.items.push({
|
|
178
|
-
type: "runway",
|
|
179
|
-
label: "Runway",
|
|
180
|
-
value: `${results.groups.runway}`
|
|
181
|
-
});
|
|
182
|
-
decodeResult.formatted.items.push({
|
|
183
|
-
type: "unknown2",
|
|
184
|
-
label: "Unknown Field 2",
|
|
185
|
-
value: `${results.groups.unknown2}`
|
|
186
|
-
});
|
|
424
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.from);
|
|
425
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
|
|
426
|
+
ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
|
|
187
427
|
} else {
|
|
188
428
|
if (options.debug) {
|
|
189
429
|
console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
|
|
@@ -206,62 +446,278 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
206
446
|
}
|
|
207
447
|
};
|
|
208
448
|
|
|
209
|
-
// lib/
|
|
210
|
-
var
|
|
449
|
+
// lib/plugins/Label_10_LDR.ts
|
|
450
|
+
var Label_10_LDR = class extends DecoderPlugin {
|
|
451
|
+
// eslint-disable-line camelcase
|
|
452
|
+
name = "label-10-ldr";
|
|
453
|
+
qualifiers() {
|
|
454
|
+
return {
|
|
455
|
+
labels: ["10"],
|
|
456
|
+
preambles: ["LDR"]
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
decode(message, options = {}) {
|
|
460
|
+
const decodeResult = this.defaultResult();
|
|
461
|
+
decodeResult.decoder.name = this.name;
|
|
462
|
+
decodeResult.formatted.description = "Position Report";
|
|
463
|
+
decodeResult.message = message;
|
|
464
|
+
const parts = message.text.split(",");
|
|
465
|
+
if (parts.length < 17) {
|
|
466
|
+
if (options.debug) {
|
|
467
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
468
|
+
}
|
|
469
|
+
decodeResult.remaining.text = message.text;
|
|
470
|
+
decodeResult.decoded = false;
|
|
471
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
472
|
+
return decodeResult;
|
|
473
|
+
}
|
|
474
|
+
const lat = parts[5];
|
|
475
|
+
const lon = parts[6];
|
|
476
|
+
const position = {
|
|
477
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()),
|
|
478
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim())
|
|
479
|
+
};
|
|
480
|
+
ResultFormatter.position(decodeResult, position);
|
|
481
|
+
ResultFormatter.altitude(decodeResult, Number(parts[7]));
|
|
482
|
+
ResultFormatter.departureAirport(decodeResult, parts[9]);
|
|
483
|
+
ResultFormatter.arrivalAirport(decodeResult, parts[10]);
|
|
484
|
+
ResultFormatter.alternateAirport(decodeResult, parts[11]);
|
|
485
|
+
ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
|
|
486
|
+
const altRwy = [parts[13].split("/")[0], parts[14].split("/")[0]].filter((r) => r != "").join(",");
|
|
487
|
+
if (altRwy != "") {
|
|
488
|
+
ResultFormatter.alternateRunway(decodeResult, altRwy);
|
|
489
|
+
}
|
|
490
|
+
decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
|
|
491
|
+
decodeResult.decoded = true;
|
|
492
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
493
|
+
return decodeResult;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// lib/plugins/Label_10_POS.ts
|
|
498
|
+
var Label_10_POS = class extends DecoderPlugin {
|
|
499
|
+
// eslint-disable-line camelcase
|
|
500
|
+
name = "label-10-pos";
|
|
501
|
+
qualifiers() {
|
|
502
|
+
return {
|
|
503
|
+
labels: ["10"],
|
|
504
|
+
preambles: ["POS"]
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
decode(message, options = {}) {
|
|
508
|
+
const decodeResult = this.defaultResult();
|
|
509
|
+
decodeResult.decoder.name = this.name;
|
|
510
|
+
decodeResult.formatted.description = "Position Report";
|
|
511
|
+
decodeResult.message = message;
|
|
512
|
+
const parts = message.text.split(",");
|
|
513
|
+
if (parts.length !== 12) {
|
|
514
|
+
if (options.debug) {
|
|
515
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
516
|
+
}
|
|
517
|
+
decodeResult.remaining.text = message.text;
|
|
518
|
+
decodeResult.decoded = false;
|
|
519
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
520
|
+
return decodeResult;
|
|
521
|
+
}
|
|
522
|
+
const lat = parts[1].trim();
|
|
523
|
+
const lon = parts[2].trim();
|
|
524
|
+
const position = {
|
|
525
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()) / 100,
|
|
526
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim()) / 100
|
|
527
|
+
};
|
|
528
|
+
ResultFormatter.position(decodeResult, position);
|
|
529
|
+
ResultFormatter.altitude(decodeResult, Number(parts[7]));
|
|
530
|
+
decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
|
|
531
|
+
decodeResult.decoded = true;
|
|
532
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
533
|
+
return decodeResult;
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
// lib/DateTimeUtils.ts
|
|
538
|
+
var DateTimeUtils = class {
|
|
539
|
+
// Expects a four digit UTC time string (HHMM)
|
|
540
|
+
static UTCToString(UTCString) {
|
|
541
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
542
|
+
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
543
|
+
return utcDate.toTimeString();
|
|
544
|
+
}
|
|
545
|
+
// Expects a six digit date string and a four digit UTC time string
|
|
546
|
+
// (DDMMYY) (HHMM)
|
|
547
|
+
static UTCDateTimeToString(dateString, timeString) {
|
|
548
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
549
|
+
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
550
|
+
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
551
|
+
if (dateString.length === 6) {
|
|
552
|
+
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
553
|
+
}
|
|
554
|
+
if (timeString.length === 6) {
|
|
555
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
556
|
+
} else {
|
|
557
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
558
|
+
}
|
|
559
|
+
return utcDate.toUTCString();
|
|
560
|
+
}
|
|
211
561
|
/**
|
|
212
|
-
* Decode a string of coordinates into an object with latitude and longitude in millidegrees
|
|
213
|
-
* @param stringCoords - The string of coordinates to decode
|
|
214
562
|
*
|
|
215
|
-
* @
|
|
563
|
+
* @param time HHMMSS
|
|
564
|
+
* @returns seconds since midnight
|
|
216
565
|
*/
|
|
217
|
-
static
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
566
|
+
static convertHHMMSSToTod(time) {
|
|
567
|
+
const h = Number(time.substring(0, 2));
|
|
568
|
+
const m = Number(time.substring(2, 4));
|
|
569
|
+
const s = Number(time.substring(4, 6));
|
|
570
|
+
const tod = h * 3600 + m * 60 + s;
|
|
571
|
+
return tod;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
*
|
|
575
|
+
* @param time HHMMSS
|
|
576
|
+
* @param date MMDDYY or MMDDYYYY
|
|
577
|
+
* @returns seconds since epoch
|
|
578
|
+
*/
|
|
579
|
+
static convertDateTimeToEpoch(time, date) {
|
|
580
|
+
if (date.length === 6) {
|
|
581
|
+
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
225
582
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
583
|
+
const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
|
|
584
|
+
const millis = Date.parse(timestamp);
|
|
585
|
+
return millis / 1e3;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
// lib/utils/route_utils.ts
|
|
590
|
+
var RouteUtils = class _RouteUtils {
|
|
591
|
+
static routeToString(route) {
|
|
592
|
+
let str = "";
|
|
593
|
+
if (route.name) {
|
|
594
|
+
str += route.name;
|
|
595
|
+
}
|
|
596
|
+
if (route.runway) {
|
|
597
|
+
str += `(${route.runway})`;
|
|
598
|
+
}
|
|
599
|
+
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
600
|
+
str += " starting at ";
|
|
601
|
+
} else if (str.length !== 0 && route.waypoints) {
|
|
602
|
+
str += ": ";
|
|
603
|
+
}
|
|
604
|
+
if (route.waypoints) {
|
|
605
|
+
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
606
|
+
}
|
|
607
|
+
return str;
|
|
608
|
+
}
|
|
609
|
+
static waypointToString(waypoint) {
|
|
610
|
+
let s = waypoint.name;
|
|
611
|
+
if (waypoint.latitude && waypoint.longitude) {
|
|
612
|
+
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
613
|
+
}
|
|
614
|
+
if (waypoint.offset) {
|
|
615
|
+
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
616
|
+
}
|
|
617
|
+
if (waypoint.time && waypoint.timeFormat) {
|
|
618
|
+
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
619
|
+
}
|
|
620
|
+
return s;
|
|
621
|
+
}
|
|
622
|
+
static getWaypoint(leg) {
|
|
623
|
+
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
624
|
+
if (regex?.length == 4) {
|
|
625
|
+
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
626
|
+
}
|
|
627
|
+
const waypoint = leg.split(",");
|
|
628
|
+
if (waypoint.length == 2) {
|
|
629
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
630
|
+
if (position) {
|
|
631
|
+
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (leg.length == 13 || leg.length == 14) {
|
|
635
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
636
|
+
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
637
|
+
if (position) {
|
|
638
|
+
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return { name: leg };
|
|
642
|
+
}
|
|
643
|
+
// move out if we want public
|
|
644
|
+
static timestampToString(time, format) {
|
|
645
|
+
const date = new Date(time * 1e3);
|
|
646
|
+
if (format == "tod") {
|
|
647
|
+
return date.toISOString().slice(11, 19);
|
|
648
|
+
}
|
|
649
|
+
return date.toISOString().slice(0, -5) + "Z";
|
|
650
|
+
}
|
|
651
|
+
static waypointsToString(waypoints) {
|
|
652
|
+
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
653
|
+
if (str.startsWith(" > ")) {
|
|
654
|
+
str = ">>" + str.slice(2);
|
|
231
655
|
}
|
|
232
|
-
return
|
|
656
|
+
return str;
|
|
233
657
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// lib/plugins/Label_10_Slash.ts
|
|
661
|
+
var Label_10_Slash = class extends DecoderPlugin {
|
|
662
|
+
// eslint-disable-line camelcase
|
|
663
|
+
name = "label-10-slash";
|
|
664
|
+
qualifiers() {
|
|
665
|
+
return {
|
|
666
|
+
labels: ["10"],
|
|
667
|
+
preambles: ["/"]
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
decode(message, options = {}) {
|
|
671
|
+
const decodeResult = this.defaultResult();
|
|
672
|
+
decodeResult.decoder.name = this.name;
|
|
673
|
+
decodeResult.formatted.description = "Position Report";
|
|
674
|
+
decodeResult.message = message;
|
|
675
|
+
const parts = message.text.split("/");
|
|
676
|
+
if (parts.length < 17) {
|
|
677
|
+
if (options.debug) {
|
|
678
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
679
|
+
}
|
|
680
|
+
decodeResult.remaining.text = message.text;
|
|
681
|
+
decodeResult.decoded = false;
|
|
682
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
683
|
+
return decodeResult;
|
|
248
684
|
}
|
|
249
|
-
const
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
685
|
+
const lat = parts[1];
|
|
686
|
+
const lon = parts[2];
|
|
687
|
+
const position = {
|
|
688
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
|
|
689
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
|
|
690
|
+
};
|
|
691
|
+
ResultFormatter.position(decodeResult, position);
|
|
692
|
+
ResultFormatter.heading(decodeResult, Number(parts[5]));
|
|
693
|
+
ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
|
|
694
|
+
ResultFormatter.arrivalAirport(decodeResult, parts[7]);
|
|
695
|
+
ResultFormatter.eta(decodeResult, parts[8] + "00");
|
|
696
|
+
const waypoints = [{
|
|
697
|
+
name: parts[11]
|
|
698
|
+
}, {
|
|
699
|
+
name: parts[12],
|
|
700
|
+
time: DateTimeUtils.convertHHMMSSToTod(parts[13] + "00"),
|
|
701
|
+
timeFormat: "tod"
|
|
702
|
+
}, {
|
|
703
|
+
name: parts[14],
|
|
704
|
+
time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
|
|
705
|
+
timeFormat: "tod"
|
|
706
|
+
}];
|
|
707
|
+
decodeResult.raw.route = { waypoints };
|
|
708
|
+
decodeResult.formatted.items.push({
|
|
709
|
+
type: "aircraft_route",
|
|
710
|
+
code: "ROUTE",
|
|
711
|
+
label: "Aircraft Route",
|
|
712
|
+
value: RouteUtils.routeToString(decodeResult.raw.route)
|
|
713
|
+
});
|
|
714
|
+
if (parts[16]) {
|
|
715
|
+
ResultFormatter.departureAirport(decodeResult, parts[16]);
|
|
258
716
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const lonDir = coords.longitude > 0 ? "E" : "W";
|
|
264
|
-
return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
|
|
717
|
+
decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
|
|
718
|
+
decodeResult.decoded = true;
|
|
719
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
720
|
+
return decodeResult;
|
|
265
721
|
}
|
|
266
722
|
};
|
|
267
723
|
|
|
@@ -290,19 +746,14 @@ var Label_12_N_Space = class extends DecoderPlugin {
|
|
|
290
746
|
latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
|
|
291
747
|
longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
|
|
292
748
|
};
|
|
293
|
-
|
|
749
|
+
const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
|
|
294
750
|
decodeResult.formatted.items.push({
|
|
295
751
|
type: "aircraft_position",
|
|
296
752
|
code: "POS",
|
|
297
753
|
label: "Aircraft Position",
|
|
298
754
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
299
755
|
});
|
|
300
|
-
|
|
301
|
-
type: "flight_level",
|
|
302
|
-
code: "FL",
|
|
303
|
-
label: "Flight Level",
|
|
304
|
-
value: decodeResult.raw.flight_level
|
|
305
|
-
});
|
|
756
|
+
ResultFormatter.altitude(decodeResult, altitude);
|
|
306
757
|
decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
|
|
307
758
|
decodeResult.decoded = true;
|
|
308
759
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -318,6 +769,97 @@ var Label_12_N_Space = class extends DecoderPlugin {
|
|
|
318
769
|
}
|
|
319
770
|
};
|
|
320
771
|
|
|
772
|
+
// lib/plugins/Label_13Through18_Slash.ts
|
|
773
|
+
var Label_13Through18_Slash = class extends DecoderPlugin {
|
|
774
|
+
// eslint-disable-line camelcase
|
|
775
|
+
name = "label-13-18-slash";
|
|
776
|
+
qualifiers() {
|
|
777
|
+
return {
|
|
778
|
+
labels: ["13", "14", "15", "16", "17", "18"],
|
|
779
|
+
preambles: ["/"]
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
decode(message, options = {}) {
|
|
783
|
+
const decodeResult = this.defaultResult();
|
|
784
|
+
decodeResult.decoder.name = this.name;
|
|
785
|
+
decodeResult.message = message;
|
|
786
|
+
const lines = message.text.split("\r\n");
|
|
787
|
+
const parts = lines[0].split("/");
|
|
788
|
+
const labelNumber = Number(parts[1].substring(0, 2));
|
|
789
|
+
decodeResult.formatted.description = getMsgType(labelNumber);
|
|
790
|
+
if (labelNumber !== 18 && parts.length !== 4 || labelNumber === 18 && parts.length !== 7) {
|
|
791
|
+
if (options?.debug) {
|
|
792
|
+
console.log(`Decoder: Unknown OOOI message: ${message.text}`);
|
|
793
|
+
}
|
|
794
|
+
decodeResult.remaining.text = message.text;
|
|
795
|
+
decodeResult.decoded = false;
|
|
796
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
797
|
+
return decodeResult;
|
|
798
|
+
}
|
|
799
|
+
decodeResult.remaining.text = "";
|
|
800
|
+
const data = parts[2].split(" ");
|
|
801
|
+
ResultFormatter.departureAirport(decodeResult, data[1]);
|
|
802
|
+
ResultFormatter.arrivalAirport(decodeResult, data[2]);
|
|
803
|
+
decodeResult.raw.day_of_month = Number(data[3]);
|
|
804
|
+
const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
|
|
805
|
+
if (labelNumber === 13) {
|
|
806
|
+
ResultFormatter.out(decodeResult, time);
|
|
807
|
+
} else if (labelNumber === 14) {
|
|
808
|
+
ResultFormatter.off(decodeResult, time);
|
|
809
|
+
} else if (labelNumber === 15) {
|
|
810
|
+
ResultFormatter.on(decodeResult, time);
|
|
811
|
+
} else if (labelNumber === 16) {
|
|
812
|
+
ResultFormatter.in(decodeResult, time);
|
|
813
|
+
}
|
|
814
|
+
if (parts.length === 7) {
|
|
815
|
+
decodeResult.remaining.text += parts.slice(4).join("/");
|
|
816
|
+
}
|
|
817
|
+
for (let i = 1; i < lines.length; i++) {
|
|
818
|
+
if (lines[i].startsWith("/LOC")) {
|
|
819
|
+
const location = lines[i].substring(5).split(",");
|
|
820
|
+
let position;
|
|
821
|
+
if (location[0].startsWith("+") || location[0].startsWith("-")) {
|
|
822
|
+
position = { latitude: Number(location[0]), longitude: Number(location[1]) };
|
|
823
|
+
} else {
|
|
824
|
+
position = {
|
|
825
|
+
latitude: CoordinateUtils.getDirection(location[0][0]) * CoordinateUtils.dmsToDecimalDegrees(Number(location[0].substring(1, 3)), Number(location[0].substring(3, 5)), Number(location[0].substring(5, 7))),
|
|
826
|
+
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)))
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
|
|
830
|
+
ResultFormatter.position(decodeResult, position);
|
|
831
|
+
}
|
|
832
|
+
} else {
|
|
833
|
+
decodeResult.remaining.text += "\r\n" + lines[i];
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
decodeResult.decoded = true;
|
|
837
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
838
|
+
return decodeResult;
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
function getMsgType(labelNumber) {
|
|
842
|
+
if (labelNumber === 13) {
|
|
843
|
+
return "Out of Gate Report";
|
|
844
|
+
}
|
|
845
|
+
if (labelNumber === 14) {
|
|
846
|
+
return "Takeoff Report";
|
|
847
|
+
}
|
|
848
|
+
if (labelNumber === 15) {
|
|
849
|
+
return "On Ground Report";
|
|
850
|
+
}
|
|
851
|
+
if (labelNumber === 16) {
|
|
852
|
+
return "In Gate Report";
|
|
853
|
+
}
|
|
854
|
+
if (labelNumber === 17) {
|
|
855
|
+
return "Post Report";
|
|
856
|
+
}
|
|
857
|
+
if (labelNumber === 18) {
|
|
858
|
+
return "Post Times Report";
|
|
859
|
+
}
|
|
860
|
+
return "Unknown";
|
|
861
|
+
}
|
|
862
|
+
|
|
321
863
|
// lib/plugins/Label_15.ts
|
|
322
864
|
var Label_15 = class extends DecoderPlugin {
|
|
323
865
|
name = "label-5z";
|
|
@@ -364,39 +906,35 @@ var Label_15_FST = class extends DecoderPlugin {
|
|
|
364
906
|
decodeResult.decoder.name = this.name;
|
|
365
907
|
decodeResult.formatted.description = "Position Report";
|
|
366
908
|
decodeResult.message = message;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
909
|
+
const parts = message.text.split(" ");
|
|
910
|
+
const header = parts[0];
|
|
911
|
+
decodeResult.raw.departure_icao = header.substring(5, 9);
|
|
912
|
+
decodeResult.raw.arrival_icao = header.substring(9, 13);
|
|
913
|
+
const stringCoords = header.substring(13);
|
|
370
914
|
const firstChar = stringCoords.substring(0, 1);
|
|
371
915
|
const middleChar = stringCoords.substring(7, 8);
|
|
372
916
|
decodeResult.raw.position = {};
|
|
373
917
|
if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
|
|
374
918
|
decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
|
|
375
|
-
decodeResult.raw.position.longitude = Number(stringCoords.substring(8,
|
|
919
|
+
decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
|
|
920
|
+
decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
|
|
376
921
|
} else {
|
|
377
922
|
decodeResult.decoded = false;
|
|
378
923
|
decodeResult.decoder.decodeLevel = "none";
|
|
379
924
|
return decodeResult;
|
|
380
925
|
}
|
|
381
926
|
decodeResult.formatted.items.push({
|
|
382
|
-
type: "
|
|
383
|
-
|
|
927
|
+
type: "aircraft_position",
|
|
928
|
+
code: "POS",
|
|
929
|
+
label: "Aircraft Position",
|
|
384
930
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
385
931
|
});
|
|
386
|
-
decodeResult.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
value: decodeResult.raw.departure_icao
|
|
391
|
-
});
|
|
392
|
-
decodeResult.formatted.items.push({
|
|
393
|
-
type: "destination",
|
|
394
|
-
code: "DST",
|
|
395
|
-
label: "Destination",
|
|
396
|
-
value: decodeResult.raw.arrival_icao
|
|
397
|
-
});
|
|
932
|
+
ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
|
|
933
|
+
ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
|
|
934
|
+
ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
|
|
935
|
+
decodeResult.remaining.text = parts.slice(1).join(" ");
|
|
398
936
|
decodeResult.decoded = true;
|
|
399
|
-
decodeResult.decoder.decodeLevel = "
|
|
937
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
400
938
|
return decodeResult;
|
|
401
939
|
}
|
|
402
940
|
};
|
|
@@ -427,19 +965,14 @@ var Label_16_N_Space = class extends DecoderPlugin {
|
|
|
427
965
|
latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
|
|
428
966
|
longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
|
|
429
967
|
};
|
|
430
|
-
|
|
968
|
+
const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
|
|
431
969
|
decodeResult.formatted.items.push({
|
|
432
970
|
type: "aircraft_position",
|
|
433
971
|
code: "POS",
|
|
434
972
|
label: "Aircraft Position",
|
|
435
973
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
436
974
|
});
|
|
437
|
-
|
|
438
|
-
type: "flight_level",
|
|
439
|
-
code: "FL",
|
|
440
|
-
label: "Flight Level",
|
|
441
|
-
value: decodeResult.raw.flight_level
|
|
442
|
-
});
|
|
975
|
+
ResultFormatter.altitude(decodeResult, altitude);
|
|
443
976
|
decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
|
|
444
977
|
decodeResult.decoded = true;
|
|
445
978
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -472,58 +1005,6 @@ var Label_16_N_Space = class extends DecoderPlugin {
|
|
|
472
1005
|
}
|
|
473
1006
|
};
|
|
474
1007
|
|
|
475
|
-
// lib/DateTimeUtils.ts
|
|
476
|
-
var DateTimeUtils = class {
|
|
477
|
-
// Expects a four digit UTC time string (HHMM)
|
|
478
|
-
static UTCToString(UTCString) {
|
|
479
|
-
let utcDate = /* @__PURE__ */ new Date();
|
|
480
|
-
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
481
|
-
return utcDate.toTimeString();
|
|
482
|
-
}
|
|
483
|
-
// Expects a six digit date string and a four digit UTC time string
|
|
484
|
-
// (DDMMYY) (HHMM)
|
|
485
|
-
static UTCDateTimeToString(dateString, timeString) {
|
|
486
|
-
let utcDate = /* @__PURE__ */ new Date();
|
|
487
|
-
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
488
|
-
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
489
|
-
if (dateString.length === 6) {
|
|
490
|
-
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
491
|
-
}
|
|
492
|
-
if (timeString.length === 6) {
|
|
493
|
-
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
494
|
-
} else {
|
|
495
|
-
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
496
|
-
}
|
|
497
|
-
return utcDate.toUTCString();
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
*
|
|
501
|
-
* @param time HHMMSS
|
|
502
|
-
* @returns seconds since midnight
|
|
503
|
-
*/
|
|
504
|
-
static convertHHMMSSToTod(time) {
|
|
505
|
-
const h = Number(time.substring(0, 2));
|
|
506
|
-
const m = Number(time.substring(2, 4));
|
|
507
|
-
const s = Number(time.substring(4, 6));
|
|
508
|
-
const tod = h * 3600 + m * 60 + s;
|
|
509
|
-
return tod;
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
*
|
|
513
|
-
* @param time HHMMSS
|
|
514
|
-
* @param date MMDDYY or MMDDYYYY
|
|
515
|
-
* @returns seconds since epoch
|
|
516
|
-
*/
|
|
517
|
-
static convertDateTimeToEpoch(time, date) {
|
|
518
|
-
if (date.length === 6) {
|
|
519
|
-
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
520
|
-
}
|
|
521
|
-
const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
|
|
522
|
-
const millis = Date.parse(timestamp);
|
|
523
|
-
return millis / 1e3;
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
|
|
527
1008
|
// lib/plugins/Label_1M_Slash.ts
|
|
528
1009
|
var Label_1M_Slash = class extends DecoderPlugin {
|
|
529
1010
|
name = "label-1m-slash";
|
|
@@ -590,16 +1071,17 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
590
1071
|
decodeResult.message = message;
|
|
591
1072
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
592
1073
|
const content = message.text.substring(3);
|
|
593
|
-
console.log("Content: " + content);
|
|
594
1074
|
const fields = content.split(",");
|
|
595
|
-
console.log("Field Count: " + fields.length);
|
|
596
1075
|
if (fields.length == 11) {
|
|
597
|
-
|
|
1076
|
+
if (options.debug) {
|
|
1077
|
+
console.log(`DEBUG: ${this.name}: Variation 1 detected`);
|
|
1078
|
+
}
|
|
598
1079
|
const rawCoords = fields[0];
|
|
599
1080
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
600
1081
|
if (decodeResult.raw.position) {
|
|
601
1082
|
decodeResult.formatted.items.push({
|
|
602
1083
|
type: "position",
|
|
1084
|
+
code: "POS",
|
|
603
1085
|
label: "Position",
|
|
604
1086
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
605
1087
|
});
|
|
@@ -607,12 +1089,15 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
607
1089
|
decodeResult.decoded = true;
|
|
608
1090
|
decodeResult.decoder.decodeLevel = "full";
|
|
609
1091
|
} else if (fields.length == 5) {
|
|
610
|
-
|
|
1092
|
+
if (options.debug) {
|
|
1093
|
+
console.log(`DEBUG: ${this.name}: Variation 2 detected`);
|
|
1094
|
+
}
|
|
611
1095
|
const rawCoords = fields[0];
|
|
612
1096
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
613
1097
|
if (decodeResult.raw.position) {
|
|
614
1098
|
decodeResult.formatted.items.push({
|
|
615
1099
|
type: "position",
|
|
1100
|
+
code: "POS",
|
|
616
1101
|
label: "Position",
|
|
617
1102
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
618
1103
|
});
|
|
@@ -620,7 +1105,9 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
620
1105
|
decodeResult.decoded = true;
|
|
621
1106
|
decodeResult.decoder.decodeLevel = "full";
|
|
622
1107
|
} else {
|
|
623
|
-
|
|
1108
|
+
if (options.debug) {
|
|
1109
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1110
|
+
}
|
|
624
1111
|
decodeResult.decoded = false;
|
|
625
1112
|
decodeResult.decoder.decodeLevel = "none";
|
|
626
1113
|
}
|
|
@@ -644,15 +1131,13 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
644
1131
|
decodeResult.message = message;
|
|
645
1132
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
646
1133
|
const content = message.text.substring(3);
|
|
647
|
-
console.log("Content: " + content);
|
|
648
1134
|
const fields = content.split(",");
|
|
649
|
-
console.log("Field Count: " + fields.length);
|
|
650
1135
|
if (fields.length == 9) {
|
|
651
1136
|
processPosition(decodeResult, fields[0].trim());
|
|
652
1137
|
processAlt(decodeResult, fields[3]);
|
|
653
1138
|
processTemp(decodeResult, fields[6]);
|
|
654
1139
|
processArrvApt(decodeResult, fields[8]);
|
|
655
|
-
decodeResult.
|
|
1140
|
+
decodeResult.remaining.text = [
|
|
656
1141
|
fields[1],
|
|
657
1142
|
fields[2],
|
|
658
1143
|
fields[4],
|
|
@@ -662,7 +1147,9 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
662
1147
|
decodeResult.decoded = true;
|
|
663
1148
|
decodeResult.decoder.decodeLevel = "partial";
|
|
664
1149
|
} else {
|
|
665
|
-
|
|
1150
|
+
if (options.debug) {
|
|
1151
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1152
|
+
}
|
|
666
1153
|
decodeResult.decoded = false;
|
|
667
1154
|
decodeResult.decoder.decodeLevel = "none";
|
|
668
1155
|
}
|
|
@@ -1016,9 +1503,7 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1016
1503
|
console.log(results.groups);
|
|
1017
1504
|
}
|
|
1018
1505
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
|
|
1019
|
-
|
|
1020
|
-
decodeResult.raw.departure_icao = results.groups.departure_icao;
|
|
1021
|
-
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
1506
|
+
const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
|
|
1022
1507
|
decodeResult.raw.current_time = Date.parse(
|
|
1023
1508
|
(/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
|
|
1024
1509
|
);
|
|
@@ -1036,24 +1521,9 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1036
1521
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
1037
1522
|
});
|
|
1038
1523
|
}
|
|
1039
|
-
decodeResult.
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
label: "Origin",
|
|
1043
|
-
value: decodeResult.raw.departure_icao
|
|
1044
|
-
});
|
|
1045
|
-
decodeResult.formatted.items.push({
|
|
1046
|
-
type: "destination",
|
|
1047
|
-
code: "DST",
|
|
1048
|
-
label: "Destination",
|
|
1049
|
-
value: decodeResult.raw.arrival_icao
|
|
1050
|
-
});
|
|
1051
|
-
decodeResult.formatted.items.push({
|
|
1052
|
-
type: "flight_level",
|
|
1053
|
-
code: "FL",
|
|
1054
|
-
label: "Flight Level",
|
|
1055
|
-
value: decodeResult.raw.flight_level
|
|
1056
|
-
});
|
|
1524
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
|
|
1525
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
|
|
1526
|
+
ResultFormatter.altitude(decodeResult, flight_level * 100);
|
|
1057
1527
|
}
|
|
1058
1528
|
decodeResult.decoded = true;
|
|
1059
1529
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -1061,6 +1531,64 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1061
1531
|
}
|
|
1062
1532
|
};
|
|
1063
1533
|
|
|
1534
|
+
// lib/plugins/Label_4N.ts
|
|
1535
|
+
var Label_4N = class extends DecoderPlugin {
|
|
1536
|
+
name = "label-4n";
|
|
1537
|
+
qualifiers() {
|
|
1538
|
+
return {
|
|
1539
|
+
labels: ["4N"]
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
decode(message, options = {}) {
|
|
1543
|
+
const decodeResult = this.defaultResult();
|
|
1544
|
+
decodeResult.decoder.name = this.name;
|
|
1545
|
+
decodeResult.message = message;
|
|
1546
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
1547
|
+
let text = message.text;
|
|
1548
|
+
if (text.match(/^M\d{2}A\w{6}/)) {
|
|
1549
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1550
|
+
text = text.substring(10);
|
|
1551
|
+
}
|
|
1552
|
+
decodeResult.decoded = true;
|
|
1553
|
+
const fields = text.split(",");
|
|
1554
|
+
if (text.length === 51) {
|
|
1555
|
+
decodeResult.raw.day_of_month = text.substring(0, 2);
|
|
1556
|
+
ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
|
|
1557
|
+
ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
|
|
1558
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
|
|
1559
|
+
ResultFormatter.altitude(decodeResult, text.substring(48, 51) * 100);
|
|
1560
|
+
decodeResult.remaining.text = [text.substring(2, 4), text.substring(19, 29)].join(" ");
|
|
1561
|
+
} else if (fields.length === 33) {
|
|
1562
|
+
decodeResult.raw.date = fields[3];
|
|
1563
|
+
if (fields[1] === "B") {
|
|
1564
|
+
ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
|
|
1565
|
+
ResultFormatter.altitude(decodeResult, fields[6]);
|
|
1566
|
+
}
|
|
1567
|
+
ResultFormatter.departureAirport(decodeResult, fields[8]);
|
|
1568
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[9]);
|
|
1569
|
+
ResultFormatter.alternateAirport(decodeResult, fields[10]);
|
|
1570
|
+
ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
|
|
1571
|
+
if (fields[12].length > 1) {
|
|
1572
|
+
ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
|
|
1573
|
+
}
|
|
1574
|
+
ResultFormatter.checksum(decodeResult, fields[32]);
|
|
1575
|
+
decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
|
|
1576
|
+
} else {
|
|
1577
|
+
decodeResult.decoded = false;
|
|
1578
|
+
decodeResult.remaining.text = text;
|
|
1579
|
+
}
|
|
1580
|
+
if (decodeResult.decoded) {
|
|
1581
|
+
if (decodeResult.remaining.text === "")
|
|
1582
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1583
|
+
else
|
|
1584
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1585
|
+
} else {
|
|
1586
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1587
|
+
}
|
|
1588
|
+
return decodeResult;
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1064
1592
|
// lib/plugins/Label_80.ts
|
|
1065
1593
|
var Label_80 = class extends DecoderPlugin {
|
|
1066
1594
|
name = "label-80";
|
|
@@ -1092,27 +1620,15 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1092
1620
|
const parts = message.text.split("\n");
|
|
1093
1621
|
let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
|
|
1094
1622
|
let results = parts[0].match(posRptRegex);
|
|
1623
|
+
if (!results?.groups) {
|
|
1624
|
+
decodeResult.decoded = false;
|
|
1625
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1626
|
+
return decodeResult;
|
|
1627
|
+
}
|
|
1095
1628
|
if (results && results.length > 0) {
|
|
1096
|
-
decodeResult
|
|
1097
|
-
decodeResult.
|
|
1098
|
-
|
|
1099
|
-
code: "ORG",
|
|
1100
|
-
label: "Origin",
|
|
1101
|
-
value: `${results.groups.orig}`
|
|
1102
|
-
});
|
|
1103
|
-
decodeResult.raw.destination = results.groups.dest;
|
|
1104
|
-
decodeResult.formatted.items.push({
|
|
1105
|
-
type: "destination",
|
|
1106
|
-
code: "DST",
|
|
1107
|
-
label: "Destination",
|
|
1108
|
-
value: `${results.groups.dest}`
|
|
1109
|
-
});
|
|
1110
|
-
decodeResult.raw.tail = results.groups.tail;
|
|
1111
|
-
decodeResult.formatted.items.push({
|
|
1112
|
-
type: "tail",
|
|
1113
|
-
label: "Tail",
|
|
1114
|
-
value: `${results.groups.tail}`
|
|
1115
|
-
});
|
|
1629
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.orig);
|
|
1630
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
|
|
1631
|
+
ResultFormatter.tail(decodeResult, results.groups.tail);
|
|
1116
1632
|
if (results.groups.agate) {
|
|
1117
1633
|
decodeResult.raw.arrival_gate = results.groups.agate;
|
|
1118
1634
|
decodeResult.formatted.items.push({
|
|
@@ -1134,15 +1650,9 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1134
1650
|
for (const part of remainingParts) {
|
|
1135
1651
|
const matches = part.matchAll(posRptRegex);
|
|
1136
1652
|
for (const match of matches) {
|
|
1137
|
-
switch (match.groups
|
|
1653
|
+
switch (match.groups?.field) {
|
|
1138
1654
|
case "ALT": {
|
|
1139
|
-
|
|
1140
|
-
decodeResult.formatted.items.push({
|
|
1141
|
-
type: "altitude",
|
|
1142
|
-
code: "ALT",
|
|
1143
|
-
label: this.descriptions[match.groups.field],
|
|
1144
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1145
|
-
});
|
|
1655
|
+
ResultFormatter.altitude(decodeResult, Number(match.groups.value));
|
|
1146
1656
|
break;
|
|
1147
1657
|
}
|
|
1148
1658
|
case "DWND": {
|
|
@@ -1156,13 +1666,8 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1156
1666
|
break;
|
|
1157
1667
|
}
|
|
1158
1668
|
case "FL": {
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
type: "flight_level",
|
|
1162
|
-
code: "FL",
|
|
1163
|
-
label: this.descriptions[match.groups.field],
|
|
1164
|
-
value: decodeResult.raw.flight_level
|
|
1165
|
-
});
|
|
1669
|
+
const flight_level = Number(match.groups.value);
|
|
1670
|
+
ResultFormatter.altitude(decodeResult, flight_level * 100);
|
|
1166
1671
|
break;
|
|
1167
1672
|
}
|
|
1168
1673
|
case "FOB": {
|
|
@@ -1186,7 +1691,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1186
1691
|
break;
|
|
1187
1692
|
}
|
|
1188
1693
|
case "MCH": {
|
|
1189
|
-
decodeResult.raw.mach = match.groups.value / 1e3;
|
|
1694
|
+
decodeResult.raw.mach = Number(match.groups.value) / 1e3;
|
|
1190
1695
|
decodeResult.formatted.items.push({
|
|
1191
1696
|
type: "mach",
|
|
1192
1697
|
code: "MCH",
|
|
@@ -1208,20 +1713,13 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1208
1713
|
case "POS": {
|
|
1209
1714
|
const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
|
|
1210
1715
|
const posResult = match.groups.value.match(posRegex);
|
|
1211
|
-
const lat = Number(posResult
|
|
1212
|
-
const lon = Number(posResult
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
latitude,
|
|
1217
|
-
longitude
|
|
1716
|
+
const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
|
|
1717
|
+
const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
|
|
1718
|
+
const position = {
|
|
1719
|
+
latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
|
|
1720
|
+
longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
|
|
1218
1721
|
};
|
|
1219
|
-
|
|
1220
|
-
type: "position",
|
|
1221
|
-
code: "POS",
|
|
1222
|
-
label: "Position",
|
|
1223
|
-
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
1224
|
-
});
|
|
1722
|
+
ResultFormatter.position(decodeResult, position);
|
|
1225
1723
|
break;
|
|
1226
1724
|
}
|
|
1227
1725
|
case "SWND": {
|
|
@@ -1235,7 +1733,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1235
1733
|
break;
|
|
1236
1734
|
}
|
|
1237
1735
|
default: {
|
|
1238
|
-
if (match.groups
|
|
1736
|
+
if (match.groups?.field != void 0) {
|
|
1239
1737
|
const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
|
|
1240
1738
|
decodeResult.formatted.items.push({
|
|
1241
1739
|
type: match.groups.field,
|
|
@@ -1246,10 +1744,80 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1246
1744
|
}
|
|
1247
1745
|
}
|
|
1248
1746
|
}
|
|
1249
|
-
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
decodeResult.decoded = true;
|
|
1750
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1751
|
+
}
|
|
1752
|
+
return decodeResult;
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
|
|
1756
|
+
// lib/plugins/Label_83.ts
|
|
1757
|
+
var Label_83 = class extends DecoderPlugin {
|
|
1758
|
+
name = "label-83";
|
|
1759
|
+
qualifiers() {
|
|
1760
|
+
return {
|
|
1761
|
+
labels: ["83"]
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
decode(message, options = {}) {
|
|
1765
|
+
const decodeResult = this.defaultResult();
|
|
1766
|
+
decodeResult.decoder.name = this.name;
|
|
1767
|
+
decodeResult.message = message;
|
|
1768
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
1769
|
+
let text = message.text;
|
|
1770
|
+
if (text.match(/^M\d{2}A\w{6}/)) {
|
|
1771
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1772
|
+
text = text.substring(10);
|
|
1773
|
+
}
|
|
1774
|
+
decodeResult.decoded = true;
|
|
1775
|
+
if (text.substring(0, 10) === "4DH3 ETAT2") {
|
|
1776
|
+
const fields = text.split(/\s+/);
|
|
1777
|
+
if (fields[2].length > 5) {
|
|
1778
|
+
decodeResult.raw.day_of_month = fields[2].substring(5);
|
|
1779
|
+
}
|
|
1780
|
+
decodeResult.remaining.text = fields[2].substring(0, 4);
|
|
1781
|
+
const subfields = fields[3].split("/");
|
|
1782
|
+
ResultFormatter.departureAirport(decodeResult, subfields[0]);
|
|
1783
|
+
ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
|
|
1784
|
+
ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
|
|
1785
|
+
ResultFormatter.eta(decodeResult, fields[6] + "00");
|
|
1786
|
+
} else if (text.substring(0, 5) === "001PR") {
|
|
1787
|
+
decodeResult.raw.day_of_month = text.substring(5, 7);
|
|
1788
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, "")));
|
|
1789
|
+
ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
|
|
1790
|
+
decodeResult.remaining.text = text.substring(33);
|
|
1791
|
+
} else {
|
|
1792
|
+
const fields = text.replace(/\s/g, "").split(",");
|
|
1793
|
+
if (fields.length === 9) {
|
|
1794
|
+
ResultFormatter.departureAirport(decodeResult, fields[0]);
|
|
1795
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[1]);
|
|
1796
|
+
decodeResult.raw.day_of_month = fields[2].substring(0, 2);
|
|
1797
|
+
decodeResult.raw.time = fields[2].substring(2);
|
|
1798
|
+
ResultFormatter.position(
|
|
1799
|
+
decodeResult,
|
|
1800
|
+
{
|
|
1801
|
+
latitude: Number(fields[3].replace(/\s/g, "")),
|
|
1802
|
+
longitude: Number(fields[4].replace(/\s/g, ""))
|
|
1803
|
+
}
|
|
1804
|
+
);
|
|
1805
|
+
ResultFormatter.altitude(decodeResult, fields[5]);
|
|
1806
|
+
ResultFormatter.groundspeed(decodeResult, fields[6]);
|
|
1807
|
+
ResultFormatter.heading(decodeResult, fields[7]);
|
|
1808
|
+
decodeResult.remaining.text = fields[8];
|
|
1809
|
+
} else {
|
|
1810
|
+
decodeResult.decoded = false;
|
|
1811
|
+
decodeResult.remaining.text = message.text;
|
|
1250
1812
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1813
|
+
}
|
|
1814
|
+
if (decodeResult.decoded) {
|
|
1815
|
+
if (decodeResult.remaining.text === "")
|
|
1816
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1817
|
+
else
|
|
1818
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1819
|
+
} else {
|
|
1820
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1253
1821
|
}
|
|
1254
1822
|
return decodeResult;
|
|
1255
1823
|
}
|
|
@@ -1396,183 +1964,6 @@ function processUnknown(decodeResult, value) {
|
|
|
1396
1964
|
decodeResult.remaining.text += value;
|
|
1397
1965
|
}
|
|
1398
1966
|
|
|
1399
|
-
// lib/utils/result_formatter.ts
|
|
1400
|
-
var ResultFormatter = class {
|
|
1401
|
-
static altitude(decodeResult, value) {
|
|
1402
|
-
decodeResult.raw.altitude = value;
|
|
1403
|
-
decodeResult.formatted.items.push({
|
|
1404
|
-
type: "altitude",
|
|
1405
|
-
code: "ALT",
|
|
1406
|
-
label: "Altitude",
|
|
1407
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1408
|
-
});
|
|
1409
|
-
}
|
|
1410
|
-
static flightNumber(decodeResult, value) {
|
|
1411
|
-
decodeResult.raw.flight_number = value;
|
|
1412
|
-
}
|
|
1413
|
-
static departureAirport(decodeResult, value) {
|
|
1414
|
-
decodeResult.raw.departure_icao = value;
|
|
1415
|
-
decodeResult.formatted.items.push({
|
|
1416
|
-
type: "origin",
|
|
1417
|
-
code: "ORG",
|
|
1418
|
-
label: "Origin",
|
|
1419
|
-
value: decodeResult.raw.departure_icao
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
static departureRunway(decodeResult, value) {
|
|
1423
|
-
decodeResult.raw.departure_runway = value;
|
|
1424
|
-
decodeResult.formatted.items.push({
|
|
1425
|
-
type: "runway",
|
|
1426
|
-
code: "DEPRWY",
|
|
1427
|
-
label: "Departure Runway",
|
|
1428
|
-
value: decodeResult.raw.departure_runway
|
|
1429
|
-
});
|
|
1430
|
-
}
|
|
1431
|
-
static arrivalAirport(decodeResult, value) {
|
|
1432
|
-
decodeResult.raw.arrival_icao = value;
|
|
1433
|
-
decodeResult.formatted.items.push({
|
|
1434
|
-
type: "destination",
|
|
1435
|
-
code: "DST",
|
|
1436
|
-
label: "Destination",
|
|
1437
|
-
value: decodeResult.raw.arrival_icao
|
|
1438
|
-
});
|
|
1439
|
-
}
|
|
1440
|
-
static eta(decodeResult, value) {
|
|
1441
|
-
decodeResult.formatted.items.push({
|
|
1442
|
-
type: "eta",
|
|
1443
|
-
code: "ETA",
|
|
1444
|
-
label: "Estimated Time of Arrival",
|
|
1445
|
-
value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
|
|
1446
|
-
});
|
|
1447
|
-
}
|
|
1448
|
-
static arrivalRunway(decodeResult, value) {
|
|
1449
|
-
decodeResult.raw.arrival_runway = value;
|
|
1450
|
-
decodeResult.formatted.items.push({
|
|
1451
|
-
type: "runway",
|
|
1452
|
-
label: "Arrival Runway",
|
|
1453
|
-
value: decodeResult.raw.arrival_runway
|
|
1454
|
-
});
|
|
1455
|
-
}
|
|
1456
|
-
static currentFuel(decodeResult, value) {
|
|
1457
|
-
decodeResult.raw.fuel_on_board = value;
|
|
1458
|
-
decodeResult.formatted.items.push({
|
|
1459
|
-
type: "fuel_on_board",
|
|
1460
|
-
code: "FOB",
|
|
1461
|
-
label: "Fuel On Board",
|
|
1462
|
-
value: decodeResult.raw.fuel_on_board.toString()
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
static remainingFuel(decodeResult, value) {
|
|
1466
|
-
decodeResult.raw.fuel_remaining = value;
|
|
1467
|
-
decodeResult.formatted.items.push({
|
|
1468
|
-
type: "fuel_remaining",
|
|
1469
|
-
label: "Fuel Remaining",
|
|
1470
|
-
value: decodeResult.raw.fuel_remaining.toString()
|
|
1471
|
-
});
|
|
1472
|
-
}
|
|
1473
|
-
static checksum(decodeResult, value) {
|
|
1474
|
-
decodeResult.raw.checksum = Number("0x" + value);
|
|
1475
|
-
decodeResult.formatted.items.push({
|
|
1476
|
-
type: "message_checksum",
|
|
1477
|
-
code: "CHECKSUM",
|
|
1478
|
-
label: "Message Checksum",
|
|
1479
|
-
value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
|
|
1480
|
-
});
|
|
1481
|
-
}
|
|
1482
|
-
static groundspeed(decodeResult, value) {
|
|
1483
|
-
decodeResult.raw.groundspeed = value;
|
|
1484
|
-
decodeResult.formatted.items.push({
|
|
1485
|
-
type: "aircraft_groundspeed",
|
|
1486
|
-
code: "GSPD",
|
|
1487
|
-
label: "Aircraft Groundspeed",
|
|
1488
|
-
value: `${decodeResult.raw.groundspeed}`
|
|
1489
|
-
});
|
|
1490
|
-
}
|
|
1491
|
-
static temperature(decodeResult, value) {
|
|
1492
|
-
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
1493
|
-
decodeResult.formatted.items.push({
|
|
1494
|
-
type: "outside_air_temperature",
|
|
1495
|
-
code: "OATEMP",
|
|
1496
|
-
label: "Outside Air Temperature (C)",
|
|
1497
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
1498
|
-
});
|
|
1499
|
-
}
|
|
1500
|
-
static unknown(decodeResult, value) {
|
|
1501
|
-
decodeResult.remaining.text += "," + value;
|
|
1502
|
-
}
|
|
1503
|
-
};
|
|
1504
|
-
|
|
1505
|
-
// lib/utils/route_utils.ts
|
|
1506
|
-
var RouteUtils = class _RouteUtils {
|
|
1507
|
-
static routeToString(route) {
|
|
1508
|
-
let str = "";
|
|
1509
|
-
if (route.name) {
|
|
1510
|
-
str += route.name;
|
|
1511
|
-
}
|
|
1512
|
-
if (route.runway) {
|
|
1513
|
-
str += `(${route.runway})`;
|
|
1514
|
-
}
|
|
1515
|
-
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
1516
|
-
str += " starting at ";
|
|
1517
|
-
} else if (str.length !== 0 && route.waypoints) {
|
|
1518
|
-
str += ": ";
|
|
1519
|
-
}
|
|
1520
|
-
if (route.waypoints) {
|
|
1521
|
-
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
1522
|
-
}
|
|
1523
|
-
return str;
|
|
1524
|
-
}
|
|
1525
|
-
static waypointToString(waypoint) {
|
|
1526
|
-
let s = waypoint.name;
|
|
1527
|
-
if (waypoint.latitude && waypoint.longitude) {
|
|
1528
|
-
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
1529
|
-
}
|
|
1530
|
-
if (waypoint.offset) {
|
|
1531
|
-
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
1532
|
-
}
|
|
1533
|
-
if (waypoint.time && waypoint.timeFormat) {
|
|
1534
|
-
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
1535
|
-
}
|
|
1536
|
-
return s;
|
|
1537
|
-
}
|
|
1538
|
-
static getWaypoint(leg) {
|
|
1539
|
-
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
1540
|
-
if (regex?.length == 4) {
|
|
1541
|
-
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
1542
|
-
}
|
|
1543
|
-
const waypoint = leg.split(",");
|
|
1544
|
-
if (waypoint.length == 2) {
|
|
1545
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
1546
|
-
if (position) {
|
|
1547
|
-
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
if (leg.length == 13 || leg.length == 14) {
|
|
1551
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
1552
|
-
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
1553
|
-
if (position) {
|
|
1554
|
-
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
return { name: leg };
|
|
1558
|
-
}
|
|
1559
|
-
// move out if we want public
|
|
1560
|
-
static timestampToString(time, format) {
|
|
1561
|
-
const date = new Date(time * 1e3);
|
|
1562
|
-
if (format == "tod") {
|
|
1563
|
-
return date.toISOString().slice(11, 19);
|
|
1564
|
-
}
|
|
1565
|
-
return date.toISOString().slice(0, -5) + "Z";
|
|
1566
|
-
}
|
|
1567
|
-
static waypointsToString(waypoints) {
|
|
1568
|
-
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
1569
|
-
if (str.startsWith(" > ")) {
|
|
1570
|
-
str = ">>" + str.slice(2);
|
|
1571
|
-
}
|
|
1572
|
-
return str;
|
|
1573
|
-
}
|
|
1574
|
-
};
|
|
1575
|
-
|
|
1576
1967
|
// lib/utils/flight_plan_utils.ts
|
|
1577
1968
|
var FlightPlanUtils = class _FlightPlanUtils {
|
|
1578
1969
|
/**
|
|
@@ -1834,13 +2225,7 @@ function processTimeOfDeparture(decodeResult, data) {
|
|
|
1834
2225
|
return false;
|
|
1835
2226
|
}
|
|
1836
2227
|
function processIdentification(decodeResult, data) {
|
|
1837
|
-
|
|
1838
|
-
decodeResult.formatted.items.push({
|
|
1839
|
-
type: "tail",
|
|
1840
|
-
code: "TAIL",
|
|
1841
|
-
label: "Tail",
|
|
1842
|
-
value: decodeResult.raw.tail
|
|
1843
|
-
});
|
|
2228
|
+
ResultFormatter.tail(decodeResult, data[0]);
|
|
1844
2229
|
if (data.length > 1) {
|
|
1845
2230
|
decodeResult.raw.flight_number = data[1];
|
|
1846
2231
|
}
|
|
@@ -1937,8 +2322,6 @@ function processPS(decodeResult, data) {
|
|
|
1937
2322
|
} else {
|
|
1938
2323
|
allKnownFields = false;
|
|
1939
2324
|
}
|
|
1940
|
-
console.log("PS data.length: ", data.length);
|
|
1941
|
-
console.log("PS data: ", data);
|
|
1942
2325
|
if (data.length === 9) {
|
|
1943
2326
|
processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
|
|
1944
2327
|
ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
|
|
@@ -1973,8 +2356,6 @@ function processPosition2(decodeResult, data) {
|
|
|
1973
2356
|
} else {
|
|
1974
2357
|
allKnownFields = false;
|
|
1975
2358
|
}
|
|
1976
|
-
console.log("data.length: ", data.length);
|
|
1977
|
-
console.log("data: ", data);
|
|
1978
2359
|
if (data.length >= 10) {
|
|
1979
2360
|
ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
|
|
1980
2361
|
processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
|
|
@@ -2032,7 +2413,7 @@ var Label_H1_FPN = class extends DecoderPlugin {
|
|
|
2032
2413
|
decodeResult.decoded = true;
|
|
2033
2414
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2034
2415
|
if (decodeResult.formatted.items.length === 0) {
|
|
2035
|
-
if (options
|
|
2416
|
+
if (options.debug) {
|
|
2036
2417
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2037
2418
|
}
|
|
2038
2419
|
decodeResult.remaining.text = message.text;
|
|
@@ -2062,7 +2443,7 @@ var Label_H1_FTX = class extends DecoderPlugin {
|
|
|
2062
2443
|
decodeResult.decoded = true;
|
|
2063
2444
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2064
2445
|
if (decodeResult.formatted.items.length === 0) {
|
|
2065
|
-
if (options
|
|
2446
|
+
if (options.debug) {
|
|
2066
2447
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2067
2448
|
}
|
|
2068
2449
|
decodeResult.remaining.text = message.text;
|
|
@@ -2093,7 +2474,7 @@ var Label_H1_INI = class extends DecoderPlugin {
|
|
|
2093
2474
|
decodeResult.decoded = true;
|
|
2094
2475
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2095
2476
|
if (decodeResult.formatted.items.length === 0) {
|
|
2096
|
-
if (options
|
|
2477
|
+
if (options.debug) {
|
|
2097
2478
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2098
2479
|
}
|
|
2099
2480
|
decodeResult.remaining.text = message.text;
|
|
@@ -2182,7 +2563,7 @@ var Label_H1_POS = class extends DecoderPlugin {
|
|
|
2182
2563
|
decodeResult.decoded = true;
|
|
2183
2564
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2184
2565
|
if (decodeResult.formatted.items.length === 0) {
|
|
2185
|
-
if (options
|
|
2566
|
+
if (options.debug) {
|
|
2186
2567
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2187
2568
|
}
|
|
2188
2569
|
decodeResult.remaining.text = message.text;
|
|
@@ -2249,6 +2630,60 @@ function processUnknown2(decodeResult, value) {
|
|
|
2249
2630
|
decodeResult.remaining.text += value;
|
|
2250
2631
|
}
|
|
2251
2632
|
|
|
2633
|
+
// lib/plugins/Label_HX.ts
|
|
2634
|
+
var Label_HX = class extends DecoderPlugin {
|
|
2635
|
+
name = "label-hx";
|
|
2636
|
+
qualifiers() {
|
|
2637
|
+
return {
|
|
2638
|
+
labels: ["HX"],
|
|
2639
|
+
preambles: ["RA FMT LOCATION", "RA FMT 43"]
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
decode(message, options = {}) {
|
|
2643
|
+
const decodeResult = this.defaultResult();
|
|
2644
|
+
decodeResult.decoder.name = this.name;
|
|
2645
|
+
decodeResult.message = message;
|
|
2646
|
+
decodeResult.formatted.description = "Undelivered Uplink Report";
|
|
2647
|
+
const parts = message.text.split(" ");
|
|
2648
|
+
decodeResult.decoded = true;
|
|
2649
|
+
if (parts[2] === "LOCATION") {
|
|
2650
|
+
let latdir = parts[3].substring(0, 1);
|
|
2651
|
+
let latdeg = Number(parts[3].substring(1, 3));
|
|
2652
|
+
let latmin = Number(parts[3].substring(3, 7));
|
|
2653
|
+
let londir = parts[4].substring(0, 1);
|
|
2654
|
+
let londeg = Number(parts[4].substring(1, 4));
|
|
2655
|
+
let lonmin = Number(parts[4].substring(4, 8));
|
|
2656
|
+
decodeResult.raw.position = {
|
|
2657
|
+
latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
|
|
2658
|
+
longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
|
|
2659
|
+
};
|
|
2660
|
+
decodeResult.remaining.text = parts.slice(5).join(" ");
|
|
2661
|
+
} else if (parts[2] === "43") {
|
|
2662
|
+
ResultFormatter.departureAirport(decodeResult, parts[3]);
|
|
2663
|
+
decodeResult.remaining.text = parts.slice(4).join(" ");
|
|
2664
|
+
} else {
|
|
2665
|
+
decodeResult.decoded = false;
|
|
2666
|
+
}
|
|
2667
|
+
if (decodeResult.raw.position) {
|
|
2668
|
+
decodeResult.formatted.items.push({
|
|
2669
|
+
type: "aircraft_position",
|
|
2670
|
+
code: "POS",
|
|
2671
|
+
label: "Aircraft Position",
|
|
2672
|
+
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2675
|
+
if (decodeResult.decoded) {
|
|
2676
|
+
if (decodeResult.remaining.text === "")
|
|
2677
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
2678
|
+
else
|
|
2679
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2680
|
+
} else {
|
|
2681
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
2682
|
+
}
|
|
2683
|
+
return decodeResult;
|
|
2684
|
+
}
|
|
2685
|
+
};
|
|
2686
|
+
|
|
2252
2687
|
// lib/plugins/Label_SQ.ts
|
|
2253
2688
|
var Label_SQ = class extends DecoderPlugin {
|
|
2254
2689
|
name = "label-sq";
|
|
@@ -2289,11 +2724,13 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2289
2724
|
decodeResult.formatted.items = [
|
|
2290
2725
|
{
|
|
2291
2726
|
type: "network",
|
|
2727
|
+
code: "NETT",
|
|
2292
2728
|
label: "Network",
|
|
2293
2729
|
value: formattedNetwork
|
|
2294
2730
|
},
|
|
2295
2731
|
{
|
|
2296
2732
|
type: "version",
|
|
2733
|
+
code: "VER",
|
|
2297
2734
|
label: "Version",
|
|
2298
2735
|
value: decodeResult.raw.version
|
|
2299
2736
|
}
|
|
@@ -2302,6 +2739,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2302
2739
|
if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
|
|
2303
2740
|
decodeResult.formatted.items.push({
|
|
2304
2741
|
type: "ground_station",
|
|
2742
|
+
code: "GNDSTN",
|
|
2305
2743
|
label: "Ground Station",
|
|
2306
2744
|
value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
|
|
2307
2745
|
});
|
|
@@ -2309,6 +2747,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2309
2747
|
if (decodeResult.raw.groundStation.iataCode) {
|
|
2310
2748
|
decodeResult.formatted.items.push({
|
|
2311
2749
|
type: "iataCode",
|
|
2750
|
+
code: "IATA",
|
|
2312
2751
|
label: "IATA",
|
|
2313
2752
|
value: decodeResult.raw.groundStation.iataCode
|
|
2314
2753
|
});
|
|
@@ -2316,6 +2755,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2316
2755
|
if (decodeResult.raw.groundStation.icaoCode) {
|
|
2317
2756
|
decodeResult.formatted.items.push({
|
|
2318
2757
|
type: "icaoCode",
|
|
2758
|
+
code: "ICAO",
|
|
2319
2759
|
label: "ICAO",
|
|
2320
2760
|
value: decodeResult.raw.groundStation.icaoCode
|
|
2321
2761
|
});
|
|
@@ -2323,6 +2763,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2323
2763
|
if (decodeResult.raw.groundStation.coordinates.latitude) {
|
|
2324
2764
|
decodeResult.formatted.items.push({
|
|
2325
2765
|
type: "coordinates",
|
|
2766
|
+
code: "COORD",
|
|
2326
2767
|
label: "Ground Station Location",
|
|
2327
2768
|
value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
|
|
2328
2769
|
});
|
|
@@ -2330,6 +2771,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2330
2771
|
if (decodeResult.raw.groundStation.airport) {
|
|
2331
2772
|
decodeResult.formatted.items.push({
|
|
2332
2773
|
type: "airport",
|
|
2774
|
+
code: "APT",
|
|
2333
2775
|
label: "Airport",
|
|
2334
2776
|
value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
|
|
2335
2777
|
});
|
|
@@ -2338,6 +2780,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2338
2780
|
if (decodeResult.raw.vdlFrequency) {
|
|
2339
2781
|
decodeResult.formatted.items.push({
|
|
2340
2782
|
type: "vdlFrequency",
|
|
2783
|
+
code: "VDLFRQ",
|
|
2341
2784
|
label: "VDL Frequency",
|
|
2342
2785
|
value: `${decodeResult.raw.vdlFrequency} MHz`
|
|
2343
2786
|
});
|
|
@@ -2494,31 +2937,48 @@ var Label_QQ = class extends DecoderPlugin {
|
|
|
2494
2937
|
decode(message, options = {}) {
|
|
2495
2938
|
const decodeResult = this.defaultResult();
|
|
2496
2939
|
decodeResult.decoder.name = this.name;
|
|
2497
|
-
decodeResult.
|
|
2498
|
-
decodeResult.raw.destination = message.text.substring(4, 8);
|
|
2499
|
-
decodeResult.raw.wheels_off = message.text.substring(8, 12);
|
|
2500
|
-
decodeResult.remaining.text = message.text.substring(12);
|
|
2940
|
+
decodeResult.message = message;
|
|
2501
2941
|
decodeResult.formatted.description = "OFF Report";
|
|
2502
|
-
decodeResult.
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2942
|
+
ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
|
|
2943
|
+
ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
|
|
2944
|
+
decodeResult.raw.wheels_off = message.text.substring(8, 12);
|
|
2945
|
+
if (message.text.substring(12, 19) === "\r\n001FE") {
|
|
2946
|
+
decodeResult.raw.day_of_month = message.text.substring(19, 21);
|
|
2947
|
+
decodeResult.raw.wheels_off = message.text.substring(21, 27);
|
|
2948
|
+
let latdir = message.text.substring(27, 28);
|
|
2949
|
+
let latdeg = Number(message.text.substring(28, 30));
|
|
2950
|
+
let latmin = Number(message.text.substring(30, 34));
|
|
2951
|
+
let londir = message.text.substring(34, 35);
|
|
2952
|
+
let londeg = Number(message.text.substring(35, 38));
|
|
2953
|
+
let lonmin = Number(message.text.substring(38, 42));
|
|
2954
|
+
decodeResult.raw.position = {
|
|
2955
|
+
latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
|
|
2956
|
+
longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
|
|
2957
|
+
};
|
|
2958
|
+
decodeResult.remaining.text = message.text.substring(42, 45);
|
|
2959
|
+
if (decodeResult.remaining.text !== "---") {
|
|
2960
|
+
ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
|
|
2961
|
+
} else {
|
|
2962
|
+
ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
|
|
2520
2963
|
}
|
|
2521
|
-
|
|
2964
|
+
ResultFormatter.unknown(decodeResult, message.text.substring(48));
|
|
2965
|
+
} else {
|
|
2966
|
+
decodeResult.remaining.text = message.text.substring(12);
|
|
2967
|
+
}
|
|
2968
|
+
decodeResult.formatted.items.push({
|
|
2969
|
+
type: "wheels_off",
|
|
2970
|
+
code: "WOFF",
|
|
2971
|
+
label: "Wheels OFF",
|
|
2972
|
+
value: decodeResult.raw.wheels_off
|
|
2973
|
+
});
|
|
2974
|
+
if (decodeResult.raw.position) {
|
|
2975
|
+
decodeResult.formatted.items.push({
|
|
2976
|
+
type: "aircraft_position",
|
|
2977
|
+
code: "POS",
|
|
2978
|
+
label: "Aircraft Position",
|
|
2979
|
+
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
2980
|
+
});
|
|
2981
|
+
}
|
|
2522
2982
|
decodeResult.decoded = true;
|
|
2523
2983
|
if (decodeResult.remaining.text === "")
|
|
2524
2984
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -3341,7 +3801,11 @@ var MessageDecoder = class {
|
|
|
3341
3801
|
this.debug = false;
|
|
3342
3802
|
this.registerPlugin(new Label_ColonComma(this));
|
|
3343
3803
|
this.registerPlugin(new Label_5Z(this));
|
|
3804
|
+
this.registerPlugin(new Label_10_LDR(this));
|
|
3805
|
+
this.registerPlugin(new Label_10_POS(this));
|
|
3806
|
+
this.registerPlugin(new Label_10_Slash(this));
|
|
3344
3807
|
this.registerPlugin(new Label_12_N_Space(this));
|
|
3808
|
+
this.registerPlugin(new Label_13Through18_Slash(this));
|
|
3345
3809
|
this.registerPlugin(new Label_15(this));
|
|
3346
3810
|
this.registerPlugin(new Label_15_FST(this));
|
|
3347
3811
|
this.registerPlugin(new Label_16_N_Space(this));
|
|
@@ -3353,6 +3817,7 @@ var MessageDecoder = class {
|
|
|
3353
3817
|
this.registerPlugin(new Label_44_OFF(this));
|
|
3354
3818
|
this.registerPlugin(new Label_44_ON(this));
|
|
3355
3819
|
this.registerPlugin(new Label_44_POS(this));
|
|
3820
|
+
this.registerPlugin(new Label_4N(this));
|
|
3356
3821
|
this.registerPlugin(new Label_B6_Forwardslash(this));
|
|
3357
3822
|
this.registerPlugin(new Label_H1_FPN(this));
|
|
3358
3823
|
this.registerPlugin(new Label_H1_FLR(this));
|
|
@@ -3361,7 +3826,9 @@ var MessageDecoder = class {
|
|
|
3361
3826
|
this.registerPlugin(new Label_H1_OHMA(this));
|
|
3362
3827
|
this.registerPlugin(new Label_H1_POS(this));
|
|
3363
3828
|
this.registerPlugin(new Label_H1_WRN(this));
|
|
3829
|
+
this.registerPlugin(new Label_HX(this));
|
|
3364
3830
|
this.registerPlugin(new Label_80(this));
|
|
3831
|
+
this.registerPlugin(new Label_83(this));
|
|
3365
3832
|
this.registerPlugin(new Label_8E(this));
|
|
3366
3833
|
this.registerPlugin(new Label_1M_Slash(this));
|
|
3367
3834
|
this.registerPlugin(new Label_SQ(this));
|