@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.mjs
CHANGED
|
@@ -60,6 +60,271 @@ var DecoderPlugin = class {
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
// lib/utils/coordinate_utils.ts
|
|
64
|
+
var CoordinateUtils = class {
|
|
65
|
+
/**
|
|
66
|
+
* Decode a string of coordinates into an object with latitude and longitude in millidegrees
|
|
67
|
+
* @param stringCoords - The string of coordinates to decode
|
|
68
|
+
*
|
|
69
|
+
* @returns An object with latitude and longitude properties
|
|
70
|
+
*/
|
|
71
|
+
static decodeStringCoordinates(stringCoords) {
|
|
72
|
+
var results = {};
|
|
73
|
+
const firstChar = stringCoords.substring(0, 1);
|
|
74
|
+
let middleChar = stringCoords.substring(6, 7);
|
|
75
|
+
let longitudeChars = stringCoords.substring(7, 13);
|
|
76
|
+
if (middleChar == " ") {
|
|
77
|
+
middleChar = stringCoords.substring(7, 8);
|
|
78
|
+
longitudeChars = stringCoords.substring(8, 14);
|
|
79
|
+
}
|
|
80
|
+
if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
|
|
81
|
+
results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
|
|
82
|
+
results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
|
|
83
|
+
} else {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
|
|
90
|
+
* @param stringCoords - The string of coordinates to decode
|
|
91
|
+
*
|
|
92
|
+
* @returns An object with latitude and longitude properties
|
|
93
|
+
*/
|
|
94
|
+
static decodeStringCoordinatesDecimalMinutes(stringCoords) {
|
|
95
|
+
var results = {};
|
|
96
|
+
const firstChar = stringCoords.substring(0, 1);
|
|
97
|
+
let middleChar = stringCoords.substring(6, 7);
|
|
98
|
+
let longitudeChars = stringCoords.substring(7, 13);
|
|
99
|
+
if (middleChar == " ") {
|
|
100
|
+
middleChar = stringCoords.substring(7, 8);
|
|
101
|
+
longitudeChars = stringCoords.substring(8, 14);
|
|
102
|
+
}
|
|
103
|
+
const latDeg = Math.trunc(Number(stringCoords.substring(1, 6)) / 1e3);
|
|
104
|
+
const latMin = Number(stringCoords.substring(1, 6)) % 1e3 / 10;
|
|
105
|
+
const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
|
|
106
|
+
const lonMin = Number(longitudeChars) % 1e3 / 10;
|
|
107
|
+
if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
|
|
108
|
+
results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
|
|
109
|
+
results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
|
|
110
|
+
} else {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
115
|
+
static coordinateString(coords) {
|
|
116
|
+
const latDir = coords.latitude > 0 ? "N" : "S";
|
|
117
|
+
const lonDir = coords.longitude > 0 ? "E" : "W";
|
|
118
|
+
return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
|
|
119
|
+
}
|
|
120
|
+
static getDirection(coord) {
|
|
121
|
+
if (coord.startsWith("N") || coord.startsWith("E")) {
|
|
122
|
+
return 1;
|
|
123
|
+
} else if (coord.startsWith("S") || coord.startsWith("W")) {
|
|
124
|
+
return -1;
|
|
125
|
+
}
|
|
126
|
+
return NaN;
|
|
127
|
+
}
|
|
128
|
+
static dmsToDecimalDegrees(degrees, minutes, seconds) {
|
|
129
|
+
return degrees + minutes / 60 + seconds / 3600;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// lib/utils/result_formatter.ts
|
|
134
|
+
var ResultFormatter = class {
|
|
135
|
+
static position(decodeResult, value) {
|
|
136
|
+
decodeResult.raw.position = value;
|
|
137
|
+
decodeResult.formatted.items.push({
|
|
138
|
+
type: "aircraft_position",
|
|
139
|
+
code: "POS",
|
|
140
|
+
label: "Aircraft Position",
|
|
141
|
+
value: CoordinateUtils.coordinateString(value)
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
static altitude(decodeResult, value) {
|
|
145
|
+
decodeResult.raw.altitude = value;
|
|
146
|
+
decodeResult.formatted.items.push({
|
|
147
|
+
type: "altitude",
|
|
148
|
+
code: "ALT",
|
|
149
|
+
label: "Altitude",
|
|
150
|
+
value: `${decodeResult.raw.altitude} feet`
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
static flightNumber(decodeResult, value) {
|
|
154
|
+
decodeResult.raw.flight_number = value;
|
|
155
|
+
}
|
|
156
|
+
static departureAirport(decodeResult, value) {
|
|
157
|
+
decodeResult.raw.departure_icao = value;
|
|
158
|
+
decodeResult.formatted.items.push({
|
|
159
|
+
type: "origin",
|
|
160
|
+
code: "ORG",
|
|
161
|
+
label: "Origin",
|
|
162
|
+
value: decodeResult.raw.departure_icao
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
static departureRunway(decodeResult, value) {
|
|
166
|
+
decodeResult.raw.departure_runway = value;
|
|
167
|
+
decodeResult.formatted.items.push({
|
|
168
|
+
type: "runway",
|
|
169
|
+
code: "DEPRWY",
|
|
170
|
+
label: "Departure Runway",
|
|
171
|
+
value: decodeResult.raw.departure_runway
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
static arrivalAirport(decodeResult, value) {
|
|
175
|
+
decodeResult.raw.arrival_icao = value;
|
|
176
|
+
decodeResult.formatted.items.push({
|
|
177
|
+
type: "destination",
|
|
178
|
+
code: "DST",
|
|
179
|
+
label: "Destination",
|
|
180
|
+
value: decodeResult.raw.arrival_icao
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
static alternateAirport(decodeResult, value) {
|
|
184
|
+
decodeResult.raw.alternate_icao = value;
|
|
185
|
+
decodeResult.formatted.items.push({
|
|
186
|
+
type: "destination",
|
|
187
|
+
code: "ALT_DST",
|
|
188
|
+
label: "Alternate Destination",
|
|
189
|
+
value: decodeResult.raw.alternate_icao
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// FIXME - make seconds since midnight for time of day
|
|
193
|
+
static eta(decodeResult, value) {
|
|
194
|
+
decodeResult.raw.eta_time = value;
|
|
195
|
+
decodeResult.formatted.items.push({
|
|
196
|
+
type: "eta",
|
|
197
|
+
code: "ETA",
|
|
198
|
+
label: "Estimated Time of Arrival",
|
|
199
|
+
value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
static arrivalRunway(decodeResult, value) {
|
|
203
|
+
decodeResult.raw.arrival_runway = value;
|
|
204
|
+
decodeResult.formatted.items.push({
|
|
205
|
+
type: "runway",
|
|
206
|
+
code: "ARWY",
|
|
207
|
+
label: "Arrival Runway",
|
|
208
|
+
value: decodeResult.raw.arrival_runway
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
static alternateRunway(decodeResult, value) {
|
|
212
|
+
decodeResult.raw.alternate_runway = value;
|
|
213
|
+
decodeResult.formatted.items.push({
|
|
214
|
+
type: "runway",
|
|
215
|
+
code: "ALT_ARWY",
|
|
216
|
+
label: "Alternate Runway",
|
|
217
|
+
value: decodeResult.raw.alternate_runway
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
static currentFuel(decodeResult, value) {
|
|
221
|
+
decodeResult.raw.fuel_on_board = value;
|
|
222
|
+
decodeResult.formatted.items.push({
|
|
223
|
+
type: "fuel_on_board",
|
|
224
|
+
code: "FOB",
|
|
225
|
+
label: "Fuel On Board",
|
|
226
|
+
value: decodeResult.raw.fuel_on_board.toString()
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
static remainingFuel(decodeResult, value) {
|
|
230
|
+
decodeResult.raw.fuel_remaining = value;
|
|
231
|
+
decodeResult.formatted.items.push({
|
|
232
|
+
type: "fuel_remaining",
|
|
233
|
+
code: "FUEL",
|
|
234
|
+
label: "Fuel Remaining",
|
|
235
|
+
value: decodeResult.raw.fuel_remaining.toString()
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
static checksum(decodeResult, value) {
|
|
239
|
+
decodeResult.raw.checksum = Number("0x" + value);
|
|
240
|
+
decodeResult.formatted.items.push({
|
|
241
|
+
type: "message_checksum",
|
|
242
|
+
code: "CHECKSUM",
|
|
243
|
+
label: "Message Checksum",
|
|
244
|
+
value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
static groundspeed(decodeResult, value) {
|
|
248
|
+
decodeResult.raw.groundspeed = value;
|
|
249
|
+
decodeResult.formatted.items.push({
|
|
250
|
+
type: "aircraft_groundspeed",
|
|
251
|
+
code: "GSPD",
|
|
252
|
+
label: "Aircraft Groundspeed",
|
|
253
|
+
value: `${decodeResult.raw.groundspeed} knots`
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
static temperature(decodeResult, value) {
|
|
257
|
+
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
258
|
+
decodeResult.formatted.items.push({
|
|
259
|
+
type: "outside_air_temperature",
|
|
260
|
+
code: "OATEMP",
|
|
261
|
+
label: "Outside Air Temperature (C)",
|
|
262
|
+
value: `${decodeResult.raw.outside_air_temperature}`
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
static heading(decodeResult, value) {
|
|
266
|
+
decodeResult.raw.heading = value;
|
|
267
|
+
decodeResult.formatted.items.push({
|
|
268
|
+
type: "heading",
|
|
269
|
+
code: "HDG",
|
|
270
|
+
label: "Heading",
|
|
271
|
+
value: `${decodeResult.raw.heading}`
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
static tail(decodeResult, value) {
|
|
275
|
+
decodeResult.raw.tail = value;
|
|
276
|
+
decodeResult.formatted.items.push({
|
|
277
|
+
type: "tail",
|
|
278
|
+
code: "TAIL",
|
|
279
|
+
label: "Tail",
|
|
280
|
+
value: decodeResult.raw.tail
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
static out(decodeResult, time) {
|
|
284
|
+
decodeResult.raw.out_time = time;
|
|
285
|
+
const date = new Date(time * 1e3);
|
|
286
|
+
decodeResult.formatted.items.push({
|
|
287
|
+
type: "time_of_day",
|
|
288
|
+
code: "OUT",
|
|
289
|
+
label: "Out of Gate Time",
|
|
290
|
+
value: date.toISOString().slice(11, 19)
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
static off(decodeResult, time) {
|
|
294
|
+
decodeResult.raw.off_time = time;
|
|
295
|
+
const date = new Date(time * 1e3);
|
|
296
|
+
decodeResult.formatted.items.push({
|
|
297
|
+
type: "time_of_day",
|
|
298
|
+
code: "OFF",
|
|
299
|
+
label: "Takeoff Time",
|
|
300
|
+
value: date.toISOString().slice(11, 19)
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
static on(decodeResult, time) {
|
|
304
|
+
decodeResult.raw.on_time = time;
|
|
305
|
+
const date = new Date(time * 1e3);
|
|
306
|
+
decodeResult.formatted.items.push({
|
|
307
|
+
type: "time_of_day",
|
|
308
|
+
code: "ON",
|
|
309
|
+
label: "Landing Time",
|
|
310
|
+
value: date.toISOString().slice(11, 19)
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
static in(decodeResult, time) {
|
|
314
|
+
decodeResult.raw.in_time = time;
|
|
315
|
+
const date = new Date(time * 1e3);
|
|
316
|
+
decodeResult.formatted.items.push({
|
|
317
|
+
type: "time_of_day",
|
|
318
|
+
code: "IN",
|
|
319
|
+
label: "In Gate Time",
|
|
320
|
+
value: date.toISOString().slice(11, 19)
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
static unknown(decodeResult, value) {
|
|
324
|
+
decodeResult.remaining.text += "," + value;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
63
328
|
// lib/plugins/Label_5Z.ts
|
|
64
329
|
var Label_5Z = class extends DecoderPlugin {
|
|
65
330
|
name = "label-5z";
|
|
@@ -119,34 +384,9 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
119
384
|
const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
|
|
120
385
|
results = remainder.match(rdcRegex);
|
|
121
386
|
if (results) {
|
|
122
|
-
decodeResult
|
|
123
|
-
decodeResult.
|
|
124
|
-
|
|
125
|
-
label: "Origin",
|
|
126
|
-
value: `${results.groups.from}`
|
|
127
|
-
});
|
|
128
|
-
decodeResult.raw.destination = results.groups.to;
|
|
129
|
-
decodeResult.formatted.items.push({
|
|
130
|
-
type: "destination",
|
|
131
|
-
label: "Destination",
|
|
132
|
-
value: `${results.groups.to}`
|
|
133
|
-
});
|
|
134
|
-
decodeResult.formatted.items.push({
|
|
135
|
-
type: "unknown1",
|
|
136
|
-
label: "Unknown Field 1",
|
|
137
|
-
value: `${results.groups.unknown1}`
|
|
138
|
-
});
|
|
139
|
-
decodeResult.raw.runway = results.groups.runway;
|
|
140
|
-
decodeResult.formatted.items.push({
|
|
141
|
-
type: "runway",
|
|
142
|
-
label: "Runway",
|
|
143
|
-
value: `${results.groups.runway}`
|
|
144
|
-
});
|
|
145
|
-
decodeResult.formatted.items.push({
|
|
146
|
-
type: "unknown2",
|
|
147
|
-
label: "Unknown Field 2",
|
|
148
|
-
value: `${results.groups.unknown2}`
|
|
149
|
-
});
|
|
387
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.from);
|
|
388
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
|
|
389
|
+
ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
|
|
150
390
|
} else {
|
|
151
391
|
if (options.debug) {
|
|
152
392
|
console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
|
|
@@ -169,62 +409,278 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
169
409
|
}
|
|
170
410
|
};
|
|
171
411
|
|
|
172
|
-
// lib/
|
|
173
|
-
var
|
|
412
|
+
// lib/plugins/Label_10_LDR.ts
|
|
413
|
+
var Label_10_LDR = class extends DecoderPlugin {
|
|
414
|
+
// eslint-disable-line camelcase
|
|
415
|
+
name = "label-10-ldr";
|
|
416
|
+
qualifiers() {
|
|
417
|
+
return {
|
|
418
|
+
labels: ["10"],
|
|
419
|
+
preambles: ["LDR"]
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
decode(message, options = {}) {
|
|
423
|
+
const decodeResult = this.defaultResult();
|
|
424
|
+
decodeResult.decoder.name = this.name;
|
|
425
|
+
decodeResult.formatted.description = "Position Report";
|
|
426
|
+
decodeResult.message = message;
|
|
427
|
+
const parts = message.text.split(",");
|
|
428
|
+
if (parts.length < 17) {
|
|
429
|
+
if (options.debug) {
|
|
430
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
431
|
+
}
|
|
432
|
+
decodeResult.remaining.text = message.text;
|
|
433
|
+
decodeResult.decoded = false;
|
|
434
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
435
|
+
return decodeResult;
|
|
436
|
+
}
|
|
437
|
+
const lat = parts[5];
|
|
438
|
+
const lon = parts[6];
|
|
439
|
+
const position = {
|
|
440
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()),
|
|
441
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim())
|
|
442
|
+
};
|
|
443
|
+
ResultFormatter.position(decodeResult, position);
|
|
444
|
+
ResultFormatter.altitude(decodeResult, Number(parts[7]));
|
|
445
|
+
ResultFormatter.departureAirport(decodeResult, parts[9]);
|
|
446
|
+
ResultFormatter.arrivalAirport(decodeResult, parts[10]);
|
|
447
|
+
ResultFormatter.alternateAirport(decodeResult, parts[11]);
|
|
448
|
+
ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
|
|
449
|
+
const altRwy = [parts[13].split("/")[0], parts[14].split("/")[0]].filter((r) => r != "").join(",");
|
|
450
|
+
if (altRwy != "") {
|
|
451
|
+
ResultFormatter.alternateRunway(decodeResult, altRwy);
|
|
452
|
+
}
|
|
453
|
+
decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
|
|
454
|
+
decodeResult.decoded = true;
|
|
455
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
456
|
+
return decodeResult;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// lib/plugins/Label_10_POS.ts
|
|
461
|
+
var Label_10_POS = class extends DecoderPlugin {
|
|
462
|
+
// eslint-disable-line camelcase
|
|
463
|
+
name = "label-10-pos";
|
|
464
|
+
qualifiers() {
|
|
465
|
+
return {
|
|
466
|
+
labels: ["10"],
|
|
467
|
+
preambles: ["POS"]
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
decode(message, options = {}) {
|
|
471
|
+
const decodeResult = this.defaultResult();
|
|
472
|
+
decodeResult.decoder.name = this.name;
|
|
473
|
+
decodeResult.formatted.description = "Position Report";
|
|
474
|
+
decodeResult.message = message;
|
|
475
|
+
const parts = message.text.split(",");
|
|
476
|
+
if (parts.length !== 12) {
|
|
477
|
+
if (options.debug) {
|
|
478
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
479
|
+
}
|
|
480
|
+
decodeResult.remaining.text = message.text;
|
|
481
|
+
decodeResult.decoded = false;
|
|
482
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
483
|
+
return decodeResult;
|
|
484
|
+
}
|
|
485
|
+
const lat = parts[1].trim();
|
|
486
|
+
const lon = parts[2].trim();
|
|
487
|
+
const position = {
|
|
488
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()) / 100,
|
|
489
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim()) / 100
|
|
490
|
+
};
|
|
491
|
+
ResultFormatter.position(decodeResult, position);
|
|
492
|
+
ResultFormatter.altitude(decodeResult, Number(parts[7]));
|
|
493
|
+
decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
|
|
494
|
+
decodeResult.decoded = true;
|
|
495
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
496
|
+
return decodeResult;
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// lib/DateTimeUtils.ts
|
|
501
|
+
var DateTimeUtils = class {
|
|
502
|
+
// Expects a four digit UTC time string (HHMM)
|
|
503
|
+
static UTCToString(UTCString) {
|
|
504
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
505
|
+
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
506
|
+
return utcDate.toTimeString();
|
|
507
|
+
}
|
|
508
|
+
// Expects a six digit date string and a four digit UTC time string
|
|
509
|
+
// (DDMMYY) (HHMM)
|
|
510
|
+
static UTCDateTimeToString(dateString, timeString) {
|
|
511
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
512
|
+
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
513
|
+
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
514
|
+
if (dateString.length === 6) {
|
|
515
|
+
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
516
|
+
}
|
|
517
|
+
if (timeString.length === 6) {
|
|
518
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
519
|
+
} else {
|
|
520
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
521
|
+
}
|
|
522
|
+
return utcDate.toUTCString();
|
|
523
|
+
}
|
|
174
524
|
/**
|
|
175
|
-
* Decode a string of coordinates into an object with latitude and longitude in millidegrees
|
|
176
|
-
* @param stringCoords - The string of coordinates to decode
|
|
177
525
|
*
|
|
178
|
-
* @
|
|
526
|
+
* @param time HHMMSS
|
|
527
|
+
* @returns seconds since midnight
|
|
179
528
|
*/
|
|
180
|
-
static
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
529
|
+
static convertHHMMSSToTod(time) {
|
|
530
|
+
const h = Number(time.substring(0, 2));
|
|
531
|
+
const m = Number(time.substring(2, 4));
|
|
532
|
+
const s = Number(time.substring(4, 6));
|
|
533
|
+
const tod = h * 3600 + m * 60 + s;
|
|
534
|
+
return tod;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
*
|
|
538
|
+
* @param time HHMMSS
|
|
539
|
+
* @param date MMDDYY or MMDDYYYY
|
|
540
|
+
* @returns seconds since epoch
|
|
541
|
+
*/
|
|
542
|
+
static convertDateTimeToEpoch(time, date) {
|
|
543
|
+
if (date.length === 6) {
|
|
544
|
+
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
188
545
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
546
|
+
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`;
|
|
547
|
+
const millis = Date.parse(timestamp);
|
|
548
|
+
return millis / 1e3;
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
// lib/utils/route_utils.ts
|
|
553
|
+
var RouteUtils = class _RouteUtils {
|
|
554
|
+
static routeToString(route) {
|
|
555
|
+
let str = "";
|
|
556
|
+
if (route.name) {
|
|
557
|
+
str += route.name;
|
|
558
|
+
}
|
|
559
|
+
if (route.runway) {
|
|
560
|
+
str += `(${route.runway})`;
|
|
561
|
+
}
|
|
562
|
+
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
563
|
+
str += " starting at ";
|
|
564
|
+
} else if (str.length !== 0 && route.waypoints) {
|
|
565
|
+
str += ": ";
|
|
566
|
+
}
|
|
567
|
+
if (route.waypoints) {
|
|
568
|
+
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
569
|
+
}
|
|
570
|
+
return str;
|
|
571
|
+
}
|
|
572
|
+
static waypointToString(waypoint) {
|
|
573
|
+
let s = waypoint.name;
|
|
574
|
+
if (waypoint.latitude && waypoint.longitude) {
|
|
575
|
+
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
576
|
+
}
|
|
577
|
+
if (waypoint.offset) {
|
|
578
|
+
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
579
|
+
}
|
|
580
|
+
if (waypoint.time && waypoint.timeFormat) {
|
|
581
|
+
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
582
|
+
}
|
|
583
|
+
return s;
|
|
584
|
+
}
|
|
585
|
+
static getWaypoint(leg) {
|
|
586
|
+
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
587
|
+
if (regex?.length == 4) {
|
|
588
|
+
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
589
|
+
}
|
|
590
|
+
const waypoint = leg.split(",");
|
|
591
|
+
if (waypoint.length == 2) {
|
|
592
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
593
|
+
if (position) {
|
|
594
|
+
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (leg.length == 13 || leg.length == 14) {
|
|
598
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
599
|
+
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
600
|
+
if (position) {
|
|
601
|
+
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return { name: leg };
|
|
605
|
+
}
|
|
606
|
+
// move out if we want public
|
|
607
|
+
static timestampToString(time, format) {
|
|
608
|
+
const date = new Date(time * 1e3);
|
|
609
|
+
if (format == "tod") {
|
|
610
|
+
return date.toISOString().slice(11, 19);
|
|
611
|
+
}
|
|
612
|
+
return date.toISOString().slice(0, -5) + "Z";
|
|
613
|
+
}
|
|
614
|
+
static waypointsToString(waypoints) {
|
|
615
|
+
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
616
|
+
if (str.startsWith(" > ")) {
|
|
617
|
+
str = ">>" + str.slice(2);
|
|
194
618
|
}
|
|
195
|
-
return
|
|
619
|
+
return str;
|
|
196
620
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
// lib/plugins/Label_10_Slash.ts
|
|
624
|
+
var Label_10_Slash = class extends DecoderPlugin {
|
|
625
|
+
// eslint-disable-line camelcase
|
|
626
|
+
name = "label-10-slash";
|
|
627
|
+
qualifiers() {
|
|
628
|
+
return {
|
|
629
|
+
labels: ["10"],
|
|
630
|
+
preambles: ["/"]
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
decode(message, options = {}) {
|
|
634
|
+
const decodeResult = this.defaultResult();
|
|
635
|
+
decodeResult.decoder.name = this.name;
|
|
636
|
+
decodeResult.formatted.description = "Position Report";
|
|
637
|
+
decodeResult.message = message;
|
|
638
|
+
const parts = message.text.split("/");
|
|
639
|
+
if (parts.length < 17) {
|
|
640
|
+
if (options.debug) {
|
|
641
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
642
|
+
}
|
|
643
|
+
decodeResult.remaining.text = message.text;
|
|
644
|
+
decodeResult.decoded = false;
|
|
645
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
646
|
+
return decodeResult;
|
|
211
647
|
}
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
648
|
+
const lat = parts[1];
|
|
649
|
+
const lon = parts[2];
|
|
650
|
+
const position = {
|
|
651
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
|
|
652
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
|
|
653
|
+
};
|
|
654
|
+
ResultFormatter.position(decodeResult, position);
|
|
655
|
+
ResultFormatter.heading(decodeResult, Number(parts[5]));
|
|
656
|
+
ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
|
|
657
|
+
ResultFormatter.arrivalAirport(decodeResult, parts[7]);
|
|
658
|
+
ResultFormatter.eta(decodeResult, parts[8] + "00");
|
|
659
|
+
const waypoints = [{
|
|
660
|
+
name: parts[11]
|
|
661
|
+
}, {
|
|
662
|
+
name: parts[12],
|
|
663
|
+
time: DateTimeUtils.convertHHMMSSToTod(parts[13] + "00"),
|
|
664
|
+
timeFormat: "tod"
|
|
665
|
+
}, {
|
|
666
|
+
name: parts[14],
|
|
667
|
+
time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
|
|
668
|
+
timeFormat: "tod"
|
|
669
|
+
}];
|
|
670
|
+
decodeResult.raw.route = { waypoints };
|
|
671
|
+
decodeResult.formatted.items.push({
|
|
672
|
+
type: "aircraft_route",
|
|
673
|
+
code: "ROUTE",
|
|
674
|
+
label: "Aircraft Route",
|
|
675
|
+
value: RouteUtils.routeToString(decodeResult.raw.route)
|
|
676
|
+
});
|
|
677
|
+
if (parts[16]) {
|
|
678
|
+
ResultFormatter.departureAirport(decodeResult, parts[16]);
|
|
221
679
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const lonDir = coords.longitude > 0 ? "E" : "W";
|
|
227
|
-
return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
|
|
680
|
+
decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
|
|
681
|
+
decodeResult.decoded = true;
|
|
682
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
683
|
+
return decodeResult;
|
|
228
684
|
}
|
|
229
685
|
};
|
|
230
686
|
|
|
@@ -253,19 +709,14 @@ var Label_12_N_Space = class extends DecoderPlugin {
|
|
|
253
709
|
latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
|
|
254
710
|
longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
|
|
255
711
|
};
|
|
256
|
-
|
|
712
|
+
const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
|
|
257
713
|
decodeResult.formatted.items.push({
|
|
258
714
|
type: "aircraft_position",
|
|
259
715
|
code: "POS",
|
|
260
716
|
label: "Aircraft Position",
|
|
261
717
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
262
718
|
});
|
|
263
|
-
|
|
264
|
-
type: "flight_level",
|
|
265
|
-
code: "FL",
|
|
266
|
-
label: "Flight Level",
|
|
267
|
-
value: decodeResult.raw.flight_level
|
|
268
|
-
});
|
|
719
|
+
ResultFormatter.altitude(decodeResult, altitude);
|
|
269
720
|
decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
|
|
270
721
|
decodeResult.decoded = true;
|
|
271
722
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -281,6 +732,97 @@ var Label_12_N_Space = class extends DecoderPlugin {
|
|
|
281
732
|
}
|
|
282
733
|
};
|
|
283
734
|
|
|
735
|
+
// lib/plugins/Label_13Through18_Slash.ts
|
|
736
|
+
var Label_13Through18_Slash = class extends DecoderPlugin {
|
|
737
|
+
// eslint-disable-line camelcase
|
|
738
|
+
name = "label-13-18-slash";
|
|
739
|
+
qualifiers() {
|
|
740
|
+
return {
|
|
741
|
+
labels: ["13", "14", "15", "16", "17", "18"],
|
|
742
|
+
preambles: ["/"]
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
decode(message, options = {}) {
|
|
746
|
+
const decodeResult = this.defaultResult();
|
|
747
|
+
decodeResult.decoder.name = this.name;
|
|
748
|
+
decodeResult.message = message;
|
|
749
|
+
const lines = message.text.split("\r\n");
|
|
750
|
+
const parts = lines[0].split("/");
|
|
751
|
+
const labelNumber = Number(parts[1].substring(0, 2));
|
|
752
|
+
decodeResult.formatted.description = getMsgType(labelNumber);
|
|
753
|
+
if (labelNumber !== 18 && parts.length !== 4 || labelNumber === 18 && parts.length !== 7) {
|
|
754
|
+
if (options?.debug) {
|
|
755
|
+
console.log(`Decoder: Unknown OOOI message: ${message.text}`);
|
|
756
|
+
}
|
|
757
|
+
decodeResult.remaining.text = message.text;
|
|
758
|
+
decodeResult.decoded = false;
|
|
759
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
760
|
+
return decodeResult;
|
|
761
|
+
}
|
|
762
|
+
decodeResult.remaining.text = "";
|
|
763
|
+
const data = parts[2].split(" ");
|
|
764
|
+
ResultFormatter.departureAirport(decodeResult, data[1]);
|
|
765
|
+
ResultFormatter.arrivalAirport(decodeResult, data[2]);
|
|
766
|
+
decodeResult.raw.day_of_month = Number(data[3]);
|
|
767
|
+
const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
|
|
768
|
+
if (labelNumber === 13) {
|
|
769
|
+
ResultFormatter.out(decodeResult, time);
|
|
770
|
+
} else if (labelNumber === 14) {
|
|
771
|
+
ResultFormatter.off(decodeResult, time);
|
|
772
|
+
} else if (labelNumber === 15) {
|
|
773
|
+
ResultFormatter.on(decodeResult, time);
|
|
774
|
+
} else if (labelNumber === 16) {
|
|
775
|
+
ResultFormatter.in(decodeResult, time);
|
|
776
|
+
}
|
|
777
|
+
if (parts.length === 7) {
|
|
778
|
+
decodeResult.remaining.text += parts.slice(4).join("/");
|
|
779
|
+
}
|
|
780
|
+
for (let i = 1; i < lines.length; i++) {
|
|
781
|
+
if (lines[i].startsWith("/LOC")) {
|
|
782
|
+
const location = lines[i].substring(5).split(",");
|
|
783
|
+
let position;
|
|
784
|
+
if (location[0].startsWith("+") || location[0].startsWith("-")) {
|
|
785
|
+
position = { latitude: Number(location[0]), longitude: Number(location[1]) };
|
|
786
|
+
} else {
|
|
787
|
+
position = {
|
|
788
|
+
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))),
|
|
789
|
+
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)))
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
|
|
793
|
+
ResultFormatter.position(decodeResult, position);
|
|
794
|
+
}
|
|
795
|
+
} else {
|
|
796
|
+
decodeResult.remaining.text += "\r\n" + lines[i];
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
decodeResult.decoded = true;
|
|
800
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
801
|
+
return decodeResult;
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
function getMsgType(labelNumber) {
|
|
805
|
+
if (labelNumber === 13) {
|
|
806
|
+
return "Out of Gate Report";
|
|
807
|
+
}
|
|
808
|
+
if (labelNumber === 14) {
|
|
809
|
+
return "Takeoff Report";
|
|
810
|
+
}
|
|
811
|
+
if (labelNumber === 15) {
|
|
812
|
+
return "On Ground Report";
|
|
813
|
+
}
|
|
814
|
+
if (labelNumber === 16) {
|
|
815
|
+
return "In Gate Report";
|
|
816
|
+
}
|
|
817
|
+
if (labelNumber === 17) {
|
|
818
|
+
return "Post Report";
|
|
819
|
+
}
|
|
820
|
+
if (labelNumber === 18) {
|
|
821
|
+
return "Post Times Report";
|
|
822
|
+
}
|
|
823
|
+
return "Unknown";
|
|
824
|
+
}
|
|
825
|
+
|
|
284
826
|
// lib/plugins/Label_15.ts
|
|
285
827
|
var Label_15 = class extends DecoderPlugin {
|
|
286
828
|
name = "label-5z";
|
|
@@ -327,39 +869,35 @@ var Label_15_FST = class extends DecoderPlugin {
|
|
|
327
869
|
decodeResult.decoder.name = this.name;
|
|
328
870
|
decodeResult.formatted.description = "Position Report";
|
|
329
871
|
decodeResult.message = message;
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
872
|
+
const parts = message.text.split(" ");
|
|
873
|
+
const header = parts[0];
|
|
874
|
+
decodeResult.raw.departure_icao = header.substring(5, 9);
|
|
875
|
+
decodeResult.raw.arrival_icao = header.substring(9, 13);
|
|
876
|
+
const stringCoords = header.substring(13);
|
|
333
877
|
const firstChar = stringCoords.substring(0, 1);
|
|
334
878
|
const middleChar = stringCoords.substring(7, 8);
|
|
335
879
|
decodeResult.raw.position = {};
|
|
336
880
|
if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
|
|
337
881
|
decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
|
|
338
|
-
decodeResult.raw.position.longitude = Number(stringCoords.substring(8,
|
|
882
|
+
decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
|
|
883
|
+
decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
|
|
339
884
|
} else {
|
|
340
885
|
decodeResult.decoded = false;
|
|
341
886
|
decodeResult.decoder.decodeLevel = "none";
|
|
342
887
|
return decodeResult;
|
|
343
888
|
}
|
|
344
889
|
decodeResult.formatted.items.push({
|
|
345
|
-
type: "
|
|
346
|
-
|
|
890
|
+
type: "aircraft_position",
|
|
891
|
+
code: "POS",
|
|
892
|
+
label: "Aircraft Position",
|
|
347
893
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
348
894
|
});
|
|
349
|
-
decodeResult.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
value: decodeResult.raw.departure_icao
|
|
354
|
-
});
|
|
355
|
-
decodeResult.formatted.items.push({
|
|
356
|
-
type: "destination",
|
|
357
|
-
code: "DST",
|
|
358
|
-
label: "Destination",
|
|
359
|
-
value: decodeResult.raw.arrival_icao
|
|
360
|
-
});
|
|
895
|
+
ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
|
|
896
|
+
ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
|
|
897
|
+
ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
|
|
898
|
+
decodeResult.remaining.text = parts.slice(1).join(" ");
|
|
361
899
|
decodeResult.decoded = true;
|
|
362
|
-
decodeResult.decoder.decodeLevel = "
|
|
900
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
363
901
|
return decodeResult;
|
|
364
902
|
}
|
|
365
903
|
};
|
|
@@ -390,19 +928,14 @@ var Label_16_N_Space = class extends DecoderPlugin {
|
|
|
390
928
|
latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
|
|
391
929
|
longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
|
|
392
930
|
};
|
|
393
|
-
|
|
931
|
+
const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
|
|
394
932
|
decodeResult.formatted.items.push({
|
|
395
933
|
type: "aircraft_position",
|
|
396
934
|
code: "POS",
|
|
397
935
|
label: "Aircraft Position",
|
|
398
936
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
399
937
|
});
|
|
400
|
-
|
|
401
|
-
type: "flight_level",
|
|
402
|
-
code: "FL",
|
|
403
|
-
label: "Flight Level",
|
|
404
|
-
value: decodeResult.raw.flight_level
|
|
405
|
-
});
|
|
938
|
+
ResultFormatter.altitude(decodeResult, altitude);
|
|
406
939
|
decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
|
|
407
940
|
decodeResult.decoded = true;
|
|
408
941
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -435,58 +968,6 @@ var Label_16_N_Space = class extends DecoderPlugin {
|
|
|
435
968
|
}
|
|
436
969
|
};
|
|
437
970
|
|
|
438
|
-
// lib/DateTimeUtils.ts
|
|
439
|
-
var DateTimeUtils = class {
|
|
440
|
-
// Expects a four digit UTC time string (HHMM)
|
|
441
|
-
static UTCToString(UTCString) {
|
|
442
|
-
let utcDate = /* @__PURE__ */ new Date();
|
|
443
|
-
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
444
|
-
return utcDate.toTimeString();
|
|
445
|
-
}
|
|
446
|
-
// Expects a six digit date string and a four digit UTC time string
|
|
447
|
-
// (DDMMYY) (HHMM)
|
|
448
|
-
static UTCDateTimeToString(dateString, timeString) {
|
|
449
|
-
let utcDate = /* @__PURE__ */ new Date();
|
|
450
|
-
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
451
|
-
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
452
|
-
if (dateString.length === 6) {
|
|
453
|
-
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
454
|
-
}
|
|
455
|
-
if (timeString.length === 6) {
|
|
456
|
-
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
457
|
-
} else {
|
|
458
|
-
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
459
|
-
}
|
|
460
|
-
return utcDate.toUTCString();
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
*
|
|
464
|
-
* @param time HHMMSS
|
|
465
|
-
* @returns seconds since midnight
|
|
466
|
-
*/
|
|
467
|
-
static convertHHMMSSToTod(time) {
|
|
468
|
-
const h = Number(time.substring(0, 2));
|
|
469
|
-
const m = Number(time.substring(2, 4));
|
|
470
|
-
const s = Number(time.substring(4, 6));
|
|
471
|
-
const tod = h * 3600 + m * 60 + s;
|
|
472
|
-
return tod;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
*
|
|
476
|
-
* @param time HHMMSS
|
|
477
|
-
* @param date MMDDYY or MMDDYYYY
|
|
478
|
-
* @returns seconds since epoch
|
|
479
|
-
*/
|
|
480
|
-
static convertDateTimeToEpoch(time, date) {
|
|
481
|
-
if (date.length === 6) {
|
|
482
|
-
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
483
|
-
}
|
|
484
|
-
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`;
|
|
485
|
-
const millis = Date.parse(timestamp);
|
|
486
|
-
return millis / 1e3;
|
|
487
|
-
}
|
|
488
|
-
};
|
|
489
|
-
|
|
490
971
|
// lib/plugins/Label_1M_Slash.ts
|
|
491
972
|
var Label_1M_Slash = class extends DecoderPlugin {
|
|
492
973
|
name = "label-1m-slash";
|
|
@@ -553,16 +1034,17 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
553
1034
|
decodeResult.message = message;
|
|
554
1035
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
555
1036
|
const content = message.text.substring(3);
|
|
556
|
-
console.log("Content: " + content);
|
|
557
1037
|
const fields = content.split(",");
|
|
558
|
-
console.log("Field Count: " + fields.length);
|
|
559
1038
|
if (fields.length == 11) {
|
|
560
|
-
|
|
1039
|
+
if (options.debug) {
|
|
1040
|
+
console.log(`DEBUG: ${this.name}: Variation 1 detected`);
|
|
1041
|
+
}
|
|
561
1042
|
const rawCoords = fields[0];
|
|
562
1043
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
563
1044
|
if (decodeResult.raw.position) {
|
|
564
1045
|
decodeResult.formatted.items.push({
|
|
565
1046
|
type: "position",
|
|
1047
|
+
code: "POS",
|
|
566
1048
|
label: "Position",
|
|
567
1049
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
568
1050
|
});
|
|
@@ -570,12 +1052,15 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
570
1052
|
decodeResult.decoded = true;
|
|
571
1053
|
decodeResult.decoder.decodeLevel = "full";
|
|
572
1054
|
} else if (fields.length == 5) {
|
|
573
|
-
|
|
1055
|
+
if (options.debug) {
|
|
1056
|
+
console.log(`DEBUG: ${this.name}: Variation 2 detected`);
|
|
1057
|
+
}
|
|
574
1058
|
const rawCoords = fields[0];
|
|
575
1059
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
576
1060
|
if (decodeResult.raw.position) {
|
|
577
1061
|
decodeResult.formatted.items.push({
|
|
578
1062
|
type: "position",
|
|
1063
|
+
code: "POS",
|
|
579
1064
|
label: "Position",
|
|
580
1065
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
581
1066
|
});
|
|
@@ -583,7 +1068,9 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
583
1068
|
decodeResult.decoded = true;
|
|
584
1069
|
decodeResult.decoder.decodeLevel = "full";
|
|
585
1070
|
} else {
|
|
586
|
-
|
|
1071
|
+
if (options.debug) {
|
|
1072
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1073
|
+
}
|
|
587
1074
|
decodeResult.decoded = false;
|
|
588
1075
|
decodeResult.decoder.decodeLevel = "none";
|
|
589
1076
|
}
|
|
@@ -607,15 +1094,13 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
607
1094
|
decodeResult.message = message;
|
|
608
1095
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
609
1096
|
const content = message.text.substring(3);
|
|
610
|
-
console.log("Content: " + content);
|
|
611
1097
|
const fields = content.split(",");
|
|
612
|
-
console.log("Field Count: " + fields.length);
|
|
613
1098
|
if (fields.length == 9) {
|
|
614
1099
|
processPosition(decodeResult, fields[0].trim());
|
|
615
1100
|
processAlt(decodeResult, fields[3]);
|
|
616
1101
|
processTemp(decodeResult, fields[6]);
|
|
617
1102
|
processArrvApt(decodeResult, fields[8]);
|
|
618
|
-
decodeResult.
|
|
1103
|
+
decodeResult.remaining.text = [
|
|
619
1104
|
fields[1],
|
|
620
1105
|
fields[2],
|
|
621
1106
|
fields[4],
|
|
@@ -625,7 +1110,9 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
625
1110
|
decodeResult.decoded = true;
|
|
626
1111
|
decodeResult.decoder.decodeLevel = "partial";
|
|
627
1112
|
} else {
|
|
628
|
-
|
|
1113
|
+
if (options.debug) {
|
|
1114
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1115
|
+
}
|
|
629
1116
|
decodeResult.decoded = false;
|
|
630
1117
|
decodeResult.decoder.decodeLevel = "none";
|
|
631
1118
|
}
|
|
@@ -979,9 +1466,7 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
979
1466
|
console.log(results.groups);
|
|
980
1467
|
}
|
|
981
1468
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
|
|
982
|
-
|
|
983
|
-
decodeResult.raw.departure_icao = results.groups.departure_icao;
|
|
984
|
-
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
1469
|
+
const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
|
|
985
1470
|
decodeResult.raw.current_time = Date.parse(
|
|
986
1471
|
(/* @__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"
|
|
987
1472
|
);
|
|
@@ -999,24 +1484,9 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
999
1484
|
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
1000
1485
|
});
|
|
1001
1486
|
}
|
|
1002
|
-
decodeResult.
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
label: "Origin",
|
|
1006
|
-
value: decodeResult.raw.departure_icao
|
|
1007
|
-
});
|
|
1008
|
-
decodeResult.formatted.items.push({
|
|
1009
|
-
type: "destination",
|
|
1010
|
-
code: "DST",
|
|
1011
|
-
label: "Destination",
|
|
1012
|
-
value: decodeResult.raw.arrival_icao
|
|
1013
|
-
});
|
|
1014
|
-
decodeResult.formatted.items.push({
|
|
1015
|
-
type: "flight_level",
|
|
1016
|
-
code: "FL",
|
|
1017
|
-
label: "Flight Level",
|
|
1018
|
-
value: decodeResult.raw.flight_level
|
|
1019
|
-
});
|
|
1487
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
|
|
1488
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
|
|
1489
|
+
ResultFormatter.altitude(decodeResult, flight_level * 100);
|
|
1020
1490
|
}
|
|
1021
1491
|
decodeResult.decoded = true;
|
|
1022
1492
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -1024,6 +1494,64 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1024
1494
|
}
|
|
1025
1495
|
};
|
|
1026
1496
|
|
|
1497
|
+
// lib/plugins/Label_4N.ts
|
|
1498
|
+
var Label_4N = class extends DecoderPlugin {
|
|
1499
|
+
name = "label-4n";
|
|
1500
|
+
qualifiers() {
|
|
1501
|
+
return {
|
|
1502
|
+
labels: ["4N"]
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
decode(message, options = {}) {
|
|
1506
|
+
const decodeResult = this.defaultResult();
|
|
1507
|
+
decodeResult.decoder.name = this.name;
|
|
1508
|
+
decodeResult.message = message;
|
|
1509
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
1510
|
+
let text = message.text;
|
|
1511
|
+
if (text.match(/^M\d{2}A\w{6}/)) {
|
|
1512
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1513
|
+
text = text.substring(10);
|
|
1514
|
+
}
|
|
1515
|
+
decodeResult.decoded = true;
|
|
1516
|
+
const fields = text.split(",");
|
|
1517
|
+
if (text.length === 51) {
|
|
1518
|
+
decodeResult.raw.day_of_month = text.substring(0, 2);
|
|
1519
|
+
ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
|
|
1520
|
+
ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
|
|
1521
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
|
|
1522
|
+
ResultFormatter.altitude(decodeResult, text.substring(48, 51) * 100);
|
|
1523
|
+
decodeResult.remaining.text = [text.substring(2, 4), text.substring(19, 29)].join(" ");
|
|
1524
|
+
} else if (fields.length === 33) {
|
|
1525
|
+
decodeResult.raw.date = fields[3];
|
|
1526
|
+
if (fields[1] === "B") {
|
|
1527
|
+
ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
|
|
1528
|
+
ResultFormatter.altitude(decodeResult, fields[6]);
|
|
1529
|
+
}
|
|
1530
|
+
ResultFormatter.departureAirport(decodeResult, fields[8]);
|
|
1531
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[9]);
|
|
1532
|
+
ResultFormatter.alternateAirport(decodeResult, fields[10]);
|
|
1533
|
+
ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
|
|
1534
|
+
if (fields[12].length > 1) {
|
|
1535
|
+
ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
|
|
1536
|
+
}
|
|
1537
|
+
ResultFormatter.checksum(decodeResult, fields[32]);
|
|
1538
|
+
decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
|
|
1539
|
+
} else {
|
|
1540
|
+
decodeResult.decoded = false;
|
|
1541
|
+
decodeResult.remaining.text = text;
|
|
1542
|
+
}
|
|
1543
|
+
if (decodeResult.decoded) {
|
|
1544
|
+
if (decodeResult.remaining.text === "")
|
|
1545
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1546
|
+
else
|
|
1547
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1548
|
+
} else {
|
|
1549
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1550
|
+
}
|
|
1551
|
+
return decodeResult;
|
|
1552
|
+
}
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1027
1555
|
// lib/plugins/Label_80.ts
|
|
1028
1556
|
var Label_80 = class extends DecoderPlugin {
|
|
1029
1557
|
name = "label-80";
|
|
@@ -1055,27 +1583,15 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1055
1583
|
const parts = message.text.split("\n");
|
|
1056
1584
|
let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
|
|
1057
1585
|
let results = parts[0].match(posRptRegex);
|
|
1586
|
+
if (!results?.groups) {
|
|
1587
|
+
decodeResult.decoded = false;
|
|
1588
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1589
|
+
return decodeResult;
|
|
1590
|
+
}
|
|
1058
1591
|
if (results && results.length > 0) {
|
|
1059
|
-
decodeResult
|
|
1060
|
-
decodeResult.
|
|
1061
|
-
|
|
1062
|
-
code: "ORG",
|
|
1063
|
-
label: "Origin",
|
|
1064
|
-
value: `${results.groups.orig}`
|
|
1065
|
-
});
|
|
1066
|
-
decodeResult.raw.destination = results.groups.dest;
|
|
1067
|
-
decodeResult.formatted.items.push({
|
|
1068
|
-
type: "destination",
|
|
1069
|
-
code: "DST",
|
|
1070
|
-
label: "Destination",
|
|
1071
|
-
value: `${results.groups.dest}`
|
|
1072
|
-
});
|
|
1073
|
-
decodeResult.raw.tail = results.groups.tail;
|
|
1074
|
-
decodeResult.formatted.items.push({
|
|
1075
|
-
type: "tail",
|
|
1076
|
-
label: "Tail",
|
|
1077
|
-
value: `${results.groups.tail}`
|
|
1078
|
-
});
|
|
1592
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.orig);
|
|
1593
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
|
|
1594
|
+
ResultFormatter.tail(decodeResult, results.groups.tail);
|
|
1079
1595
|
if (results.groups.agate) {
|
|
1080
1596
|
decodeResult.raw.arrival_gate = results.groups.agate;
|
|
1081
1597
|
decodeResult.formatted.items.push({
|
|
@@ -1097,15 +1613,9 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1097
1613
|
for (const part of remainingParts) {
|
|
1098
1614
|
const matches = part.matchAll(posRptRegex);
|
|
1099
1615
|
for (const match of matches) {
|
|
1100
|
-
switch (match.groups
|
|
1616
|
+
switch (match.groups?.field) {
|
|
1101
1617
|
case "ALT": {
|
|
1102
|
-
|
|
1103
|
-
decodeResult.formatted.items.push({
|
|
1104
|
-
type: "altitude",
|
|
1105
|
-
code: "ALT",
|
|
1106
|
-
label: this.descriptions[match.groups.field],
|
|
1107
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1108
|
-
});
|
|
1618
|
+
ResultFormatter.altitude(decodeResult, Number(match.groups.value));
|
|
1109
1619
|
break;
|
|
1110
1620
|
}
|
|
1111
1621
|
case "DWND": {
|
|
@@ -1119,13 +1629,8 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1119
1629
|
break;
|
|
1120
1630
|
}
|
|
1121
1631
|
case "FL": {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
type: "flight_level",
|
|
1125
|
-
code: "FL",
|
|
1126
|
-
label: this.descriptions[match.groups.field],
|
|
1127
|
-
value: decodeResult.raw.flight_level
|
|
1128
|
-
});
|
|
1632
|
+
const flight_level = Number(match.groups.value);
|
|
1633
|
+
ResultFormatter.altitude(decodeResult, flight_level * 100);
|
|
1129
1634
|
break;
|
|
1130
1635
|
}
|
|
1131
1636
|
case "FOB": {
|
|
@@ -1149,7 +1654,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1149
1654
|
break;
|
|
1150
1655
|
}
|
|
1151
1656
|
case "MCH": {
|
|
1152
|
-
decodeResult.raw.mach = match.groups.value / 1e3;
|
|
1657
|
+
decodeResult.raw.mach = Number(match.groups.value) / 1e3;
|
|
1153
1658
|
decodeResult.formatted.items.push({
|
|
1154
1659
|
type: "mach",
|
|
1155
1660
|
code: "MCH",
|
|
@@ -1171,20 +1676,13 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1171
1676
|
case "POS": {
|
|
1172
1677
|
const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
|
|
1173
1678
|
const posResult = match.groups.value.match(posRegex);
|
|
1174
|
-
const lat = Number(posResult
|
|
1175
|
-
const lon = Number(posResult
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
latitude,
|
|
1180
|
-
longitude
|
|
1679
|
+
const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
|
|
1680
|
+
const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
|
|
1681
|
+
const position = {
|
|
1682
|
+
latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
|
|
1683
|
+
longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
|
|
1181
1684
|
};
|
|
1182
|
-
|
|
1183
|
-
type: "position",
|
|
1184
|
-
code: "POS",
|
|
1185
|
-
label: "Position",
|
|
1186
|
-
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
1187
|
-
});
|
|
1685
|
+
ResultFormatter.position(decodeResult, position);
|
|
1188
1686
|
break;
|
|
1189
1687
|
}
|
|
1190
1688
|
case "SWND": {
|
|
@@ -1198,7 +1696,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1198
1696
|
break;
|
|
1199
1697
|
}
|
|
1200
1698
|
default: {
|
|
1201
|
-
if (match.groups
|
|
1699
|
+
if (match.groups?.field != void 0) {
|
|
1202
1700
|
const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
|
|
1203
1701
|
decodeResult.formatted.items.push({
|
|
1204
1702
|
type: match.groups.field,
|
|
@@ -1209,10 +1707,80 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1209
1707
|
}
|
|
1210
1708
|
}
|
|
1211
1709
|
}
|
|
1212
|
-
}
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
decodeResult.decoded = true;
|
|
1713
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1714
|
+
}
|
|
1715
|
+
return decodeResult;
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
|
|
1719
|
+
// lib/plugins/Label_83.ts
|
|
1720
|
+
var Label_83 = class extends DecoderPlugin {
|
|
1721
|
+
name = "label-83";
|
|
1722
|
+
qualifiers() {
|
|
1723
|
+
return {
|
|
1724
|
+
labels: ["83"]
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
decode(message, options = {}) {
|
|
1728
|
+
const decodeResult = this.defaultResult();
|
|
1729
|
+
decodeResult.decoder.name = this.name;
|
|
1730
|
+
decodeResult.message = message;
|
|
1731
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
1732
|
+
let text = message.text;
|
|
1733
|
+
if (text.match(/^M\d{2}A\w{6}/)) {
|
|
1734
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1735
|
+
text = text.substring(10);
|
|
1736
|
+
}
|
|
1737
|
+
decodeResult.decoded = true;
|
|
1738
|
+
if (text.substring(0, 10) === "4DH3 ETAT2") {
|
|
1739
|
+
const fields = text.split(/\s+/);
|
|
1740
|
+
if (fields[2].length > 5) {
|
|
1741
|
+
decodeResult.raw.day_of_month = fields[2].substring(5);
|
|
1742
|
+
}
|
|
1743
|
+
decodeResult.remaining.text = fields[2].substring(0, 4);
|
|
1744
|
+
const subfields = fields[3].split("/");
|
|
1745
|
+
ResultFormatter.departureAirport(decodeResult, subfields[0]);
|
|
1746
|
+
ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
|
|
1747
|
+
ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
|
|
1748
|
+
ResultFormatter.eta(decodeResult, fields[6] + "00");
|
|
1749
|
+
} else if (text.substring(0, 5) === "001PR") {
|
|
1750
|
+
decodeResult.raw.day_of_month = text.substring(5, 7);
|
|
1751
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, "")));
|
|
1752
|
+
ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
|
|
1753
|
+
decodeResult.remaining.text = text.substring(33);
|
|
1754
|
+
} else {
|
|
1755
|
+
const fields = text.replace(/\s/g, "").split(",");
|
|
1756
|
+
if (fields.length === 9) {
|
|
1757
|
+
ResultFormatter.departureAirport(decodeResult, fields[0]);
|
|
1758
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[1]);
|
|
1759
|
+
decodeResult.raw.day_of_month = fields[2].substring(0, 2);
|
|
1760
|
+
decodeResult.raw.time = fields[2].substring(2);
|
|
1761
|
+
ResultFormatter.position(
|
|
1762
|
+
decodeResult,
|
|
1763
|
+
{
|
|
1764
|
+
latitude: Number(fields[3].replace(/\s/g, "")),
|
|
1765
|
+
longitude: Number(fields[4].replace(/\s/g, ""))
|
|
1766
|
+
}
|
|
1767
|
+
);
|
|
1768
|
+
ResultFormatter.altitude(decodeResult, fields[5]);
|
|
1769
|
+
ResultFormatter.groundspeed(decodeResult, fields[6]);
|
|
1770
|
+
ResultFormatter.heading(decodeResult, fields[7]);
|
|
1771
|
+
decodeResult.remaining.text = fields[8];
|
|
1772
|
+
} else {
|
|
1773
|
+
decodeResult.decoded = false;
|
|
1774
|
+
decodeResult.remaining.text = message.text;
|
|
1213
1775
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1776
|
+
}
|
|
1777
|
+
if (decodeResult.decoded) {
|
|
1778
|
+
if (decodeResult.remaining.text === "")
|
|
1779
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1780
|
+
else
|
|
1781
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1782
|
+
} else {
|
|
1783
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1216
1784
|
}
|
|
1217
1785
|
return decodeResult;
|
|
1218
1786
|
}
|
|
@@ -1359,183 +1927,6 @@ function processUnknown(decodeResult, value) {
|
|
|
1359
1927
|
decodeResult.remaining.text += value;
|
|
1360
1928
|
}
|
|
1361
1929
|
|
|
1362
|
-
// lib/utils/result_formatter.ts
|
|
1363
|
-
var ResultFormatter = class {
|
|
1364
|
-
static altitude(decodeResult, value) {
|
|
1365
|
-
decodeResult.raw.altitude = value;
|
|
1366
|
-
decodeResult.formatted.items.push({
|
|
1367
|
-
type: "altitude",
|
|
1368
|
-
code: "ALT",
|
|
1369
|
-
label: "Altitude",
|
|
1370
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
static flightNumber(decodeResult, value) {
|
|
1374
|
-
decodeResult.raw.flight_number = value;
|
|
1375
|
-
}
|
|
1376
|
-
static departureAirport(decodeResult, value) {
|
|
1377
|
-
decodeResult.raw.departure_icao = value;
|
|
1378
|
-
decodeResult.formatted.items.push({
|
|
1379
|
-
type: "origin",
|
|
1380
|
-
code: "ORG",
|
|
1381
|
-
label: "Origin",
|
|
1382
|
-
value: decodeResult.raw.departure_icao
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
static departureRunway(decodeResult, value) {
|
|
1386
|
-
decodeResult.raw.departure_runway = value;
|
|
1387
|
-
decodeResult.formatted.items.push({
|
|
1388
|
-
type: "runway",
|
|
1389
|
-
code: "DEPRWY",
|
|
1390
|
-
label: "Departure Runway",
|
|
1391
|
-
value: decodeResult.raw.departure_runway
|
|
1392
|
-
});
|
|
1393
|
-
}
|
|
1394
|
-
static arrivalAirport(decodeResult, value) {
|
|
1395
|
-
decodeResult.raw.arrival_icao = value;
|
|
1396
|
-
decodeResult.formatted.items.push({
|
|
1397
|
-
type: "destination",
|
|
1398
|
-
code: "DST",
|
|
1399
|
-
label: "Destination",
|
|
1400
|
-
value: decodeResult.raw.arrival_icao
|
|
1401
|
-
});
|
|
1402
|
-
}
|
|
1403
|
-
static eta(decodeResult, value) {
|
|
1404
|
-
decodeResult.formatted.items.push({
|
|
1405
|
-
type: "eta",
|
|
1406
|
-
code: "ETA",
|
|
1407
|
-
label: "Estimated Time of Arrival",
|
|
1408
|
-
value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
|
|
1409
|
-
});
|
|
1410
|
-
}
|
|
1411
|
-
static arrivalRunway(decodeResult, value) {
|
|
1412
|
-
decodeResult.raw.arrival_runway = value;
|
|
1413
|
-
decodeResult.formatted.items.push({
|
|
1414
|
-
type: "runway",
|
|
1415
|
-
label: "Arrival Runway",
|
|
1416
|
-
value: decodeResult.raw.arrival_runway
|
|
1417
|
-
});
|
|
1418
|
-
}
|
|
1419
|
-
static currentFuel(decodeResult, value) {
|
|
1420
|
-
decodeResult.raw.fuel_on_board = value;
|
|
1421
|
-
decodeResult.formatted.items.push({
|
|
1422
|
-
type: "fuel_on_board",
|
|
1423
|
-
code: "FOB",
|
|
1424
|
-
label: "Fuel On Board",
|
|
1425
|
-
value: decodeResult.raw.fuel_on_board.toString()
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
static remainingFuel(decodeResult, value) {
|
|
1429
|
-
decodeResult.raw.fuel_remaining = value;
|
|
1430
|
-
decodeResult.formatted.items.push({
|
|
1431
|
-
type: "fuel_remaining",
|
|
1432
|
-
label: "Fuel Remaining",
|
|
1433
|
-
value: decodeResult.raw.fuel_remaining.toString()
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
static checksum(decodeResult, value) {
|
|
1437
|
-
decodeResult.raw.checksum = Number("0x" + value);
|
|
1438
|
-
decodeResult.formatted.items.push({
|
|
1439
|
-
type: "message_checksum",
|
|
1440
|
-
code: "CHECKSUM",
|
|
1441
|
-
label: "Message Checksum",
|
|
1442
|
-
value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
static groundspeed(decodeResult, value) {
|
|
1446
|
-
decodeResult.raw.groundspeed = value;
|
|
1447
|
-
decodeResult.formatted.items.push({
|
|
1448
|
-
type: "aircraft_groundspeed",
|
|
1449
|
-
code: "GSPD",
|
|
1450
|
-
label: "Aircraft Groundspeed",
|
|
1451
|
-
value: `${decodeResult.raw.groundspeed}`
|
|
1452
|
-
});
|
|
1453
|
-
}
|
|
1454
|
-
static temperature(decodeResult, value) {
|
|
1455
|
-
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
1456
|
-
decodeResult.formatted.items.push({
|
|
1457
|
-
type: "outside_air_temperature",
|
|
1458
|
-
code: "OATEMP",
|
|
1459
|
-
label: "Outside Air Temperature (C)",
|
|
1460
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
|
-
static unknown(decodeResult, value) {
|
|
1464
|
-
decodeResult.remaining.text += "," + value;
|
|
1465
|
-
}
|
|
1466
|
-
};
|
|
1467
|
-
|
|
1468
|
-
// lib/utils/route_utils.ts
|
|
1469
|
-
var RouteUtils = class _RouteUtils {
|
|
1470
|
-
static routeToString(route) {
|
|
1471
|
-
let str = "";
|
|
1472
|
-
if (route.name) {
|
|
1473
|
-
str += route.name;
|
|
1474
|
-
}
|
|
1475
|
-
if (route.runway) {
|
|
1476
|
-
str += `(${route.runway})`;
|
|
1477
|
-
}
|
|
1478
|
-
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
1479
|
-
str += " starting at ";
|
|
1480
|
-
} else if (str.length !== 0 && route.waypoints) {
|
|
1481
|
-
str += ": ";
|
|
1482
|
-
}
|
|
1483
|
-
if (route.waypoints) {
|
|
1484
|
-
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
1485
|
-
}
|
|
1486
|
-
return str;
|
|
1487
|
-
}
|
|
1488
|
-
static waypointToString(waypoint) {
|
|
1489
|
-
let s = waypoint.name;
|
|
1490
|
-
if (waypoint.latitude && waypoint.longitude) {
|
|
1491
|
-
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
1492
|
-
}
|
|
1493
|
-
if (waypoint.offset) {
|
|
1494
|
-
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
1495
|
-
}
|
|
1496
|
-
if (waypoint.time && waypoint.timeFormat) {
|
|
1497
|
-
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
1498
|
-
}
|
|
1499
|
-
return s;
|
|
1500
|
-
}
|
|
1501
|
-
static getWaypoint(leg) {
|
|
1502
|
-
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
1503
|
-
if (regex?.length == 4) {
|
|
1504
|
-
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
1505
|
-
}
|
|
1506
|
-
const waypoint = leg.split(",");
|
|
1507
|
-
if (waypoint.length == 2) {
|
|
1508
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
1509
|
-
if (position) {
|
|
1510
|
-
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
if (leg.length == 13 || leg.length == 14) {
|
|
1514
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
1515
|
-
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
1516
|
-
if (position) {
|
|
1517
|
-
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
return { name: leg };
|
|
1521
|
-
}
|
|
1522
|
-
// move out if we want public
|
|
1523
|
-
static timestampToString(time, format) {
|
|
1524
|
-
const date = new Date(time * 1e3);
|
|
1525
|
-
if (format == "tod") {
|
|
1526
|
-
return date.toISOString().slice(11, 19);
|
|
1527
|
-
}
|
|
1528
|
-
return date.toISOString().slice(0, -5) + "Z";
|
|
1529
|
-
}
|
|
1530
|
-
static waypointsToString(waypoints) {
|
|
1531
|
-
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
1532
|
-
if (str.startsWith(" > ")) {
|
|
1533
|
-
str = ">>" + str.slice(2);
|
|
1534
|
-
}
|
|
1535
|
-
return str;
|
|
1536
|
-
}
|
|
1537
|
-
};
|
|
1538
|
-
|
|
1539
1930
|
// lib/utils/flight_plan_utils.ts
|
|
1540
1931
|
var FlightPlanUtils = class _FlightPlanUtils {
|
|
1541
1932
|
/**
|
|
@@ -1797,13 +2188,7 @@ function processTimeOfDeparture(decodeResult, data) {
|
|
|
1797
2188
|
return false;
|
|
1798
2189
|
}
|
|
1799
2190
|
function processIdentification(decodeResult, data) {
|
|
1800
|
-
|
|
1801
|
-
decodeResult.formatted.items.push({
|
|
1802
|
-
type: "tail",
|
|
1803
|
-
code: "TAIL",
|
|
1804
|
-
label: "Tail",
|
|
1805
|
-
value: decodeResult.raw.tail
|
|
1806
|
-
});
|
|
2191
|
+
ResultFormatter.tail(decodeResult, data[0]);
|
|
1807
2192
|
if (data.length > 1) {
|
|
1808
2193
|
decodeResult.raw.flight_number = data[1];
|
|
1809
2194
|
}
|
|
@@ -1900,8 +2285,6 @@ function processPS(decodeResult, data) {
|
|
|
1900
2285
|
} else {
|
|
1901
2286
|
allKnownFields = false;
|
|
1902
2287
|
}
|
|
1903
|
-
console.log("PS data.length: ", data.length);
|
|
1904
|
-
console.log("PS data: ", data);
|
|
1905
2288
|
if (data.length === 9) {
|
|
1906
2289
|
processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
|
|
1907
2290
|
ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
|
|
@@ -1936,8 +2319,6 @@ function processPosition2(decodeResult, data) {
|
|
|
1936
2319
|
} else {
|
|
1937
2320
|
allKnownFields = false;
|
|
1938
2321
|
}
|
|
1939
|
-
console.log("data.length: ", data.length);
|
|
1940
|
-
console.log("data: ", data);
|
|
1941
2322
|
if (data.length >= 10) {
|
|
1942
2323
|
ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
|
|
1943
2324
|
processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
|
|
@@ -1995,7 +2376,7 @@ var Label_H1_FPN = class extends DecoderPlugin {
|
|
|
1995
2376
|
decodeResult.decoded = true;
|
|
1996
2377
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
1997
2378
|
if (decodeResult.formatted.items.length === 0) {
|
|
1998
|
-
if (options
|
|
2379
|
+
if (options.debug) {
|
|
1999
2380
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2000
2381
|
}
|
|
2001
2382
|
decodeResult.remaining.text = message.text;
|
|
@@ -2025,7 +2406,7 @@ var Label_H1_FTX = class extends DecoderPlugin {
|
|
|
2025
2406
|
decodeResult.decoded = true;
|
|
2026
2407
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2027
2408
|
if (decodeResult.formatted.items.length === 0) {
|
|
2028
|
-
if (options
|
|
2409
|
+
if (options.debug) {
|
|
2029
2410
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2030
2411
|
}
|
|
2031
2412
|
decodeResult.remaining.text = message.text;
|
|
@@ -2056,7 +2437,7 @@ var Label_H1_INI = class extends DecoderPlugin {
|
|
|
2056
2437
|
decodeResult.decoded = true;
|
|
2057
2438
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2058
2439
|
if (decodeResult.formatted.items.length === 0) {
|
|
2059
|
-
if (options
|
|
2440
|
+
if (options.debug) {
|
|
2060
2441
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2061
2442
|
}
|
|
2062
2443
|
decodeResult.remaining.text = message.text;
|
|
@@ -2145,7 +2526,7 @@ var Label_H1_POS = class extends DecoderPlugin {
|
|
|
2145
2526
|
decodeResult.decoded = true;
|
|
2146
2527
|
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2147
2528
|
if (decodeResult.formatted.items.length === 0) {
|
|
2148
|
-
if (options
|
|
2529
|
+
if (options.debug) {
|
|
2149
2530
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2150
2531
|
}
|
|
2151
2532
|
decodeResult.remaining.text = message.text;
|
|
@@ -2212,6 +2593,60 @@ function processUnknown2(decodeResult, value) {
|
|
|
2212
2593
|
decodeResult.remaining.text += value;
|
|
2213
2594
|
}
|
|
2214
2595
|
|
|
2596
|
+
// lib/plugins/Label_HX.ts
|
|
2597
|
+
var Label_HX = class extends DecoderPlugin {
|
|
2598
|
+
name = "label-hx";
|
|
2599
|
+
qualifiers() {
|
|
2600
|
+
return {
|
|
2601
|
+
labels: ["HX"],
|
|
2602
|
+
preambles: ["RA FMT LOCATION", "RA FMT 43"]
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
decode(message, options = {}) {
|
|
2606
|
+
const decodeResult = this.defaultResult();
|
|
2607
|
+
decodeResult.decoder.name = this.name;
|
|
2608
|
+
decodeResult.message = message;
|
|
2609
|
+
decodeResult.formatted.description = "Undelivered Uplink Report";
|
|
2610
|
+
const parts = message.text.split(" ");
|
|
2611
|
+
decodeResult.decoded = true;
|
|
2612
|
+
if (parts[2] === "LOCATION") {
|
|
2613
|
+
let latdir = parts[3].substring(0, 1);
|
|
2614
|
+
let latdeg = Number(parts[3].substring(1, 3));
|
|
2615
|
+
let latmin = Number(parts[3].substring(3, 7));
|
|
2616
|
+
let londir = parts[4].substring(0, 1);
|
|
2617
|
+
let londeg = Number(parts[4].substring(1, 4));
|
|
2618
|
+
let lonmin = Number(parts[4].substring(4, 8));
|
|
2619
|
+
decodeResult.raw.position = {
|
|
2620
|
+
latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
|
|
2621
|
+
longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
|
|
2622
|
+
};
|
|
2623
|
+
decodeResult.remaining.text = parts.slice(5).join(" ");
|
|
2624
|
+
} else if (parts[2] === "43") {
|
|
2625
|
+
ResultFormatter.departureAirport(decodeResult, parts[3]);
|
|
2626
|
+
decodeResult.remaining.text = parts.slice(4).join(" ");
|
|
2627
|
+
} else {
|
|
2628
|
+
decodeResult.decoded = false;
|
|
2629
|
+
}
|
|
2630
|
+
if (decodeResult.raw.position) {
|
|
2631
|
+
decodeResult.formatted.items.push({
|
|
2632
|
+
type: "aircraft_position",
|
|
2633
|
+
code: "POS",
|
|
2634
|
+
label: "Aircraft Position",
|
|
2635
|
+
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
if (decodeResult.decoded) {
|
|
2639
|
+
if (decodeResult.remaining.text === "")
|
|
2640
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
2641
|
+
else
|
|
2642
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2643
|
+
} else {
|
|
2644
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
2645
|
+
}
|
|
2646
|
+
return decodeResult;
|
|
2647
|
+
}
|
|
2648
|
+
};
|
|
2649
|
+
|
|
2215
2650
|
// lib/plugins/Label_SQ.ts
|
|
2216
2651
|
var Label_SQ = class extends DecoderPlugin {
|
|
2217
2652
|
name = "label-sq";
|
|
@@ -2252,11 +2687,13 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2252
2687
|
decodeResult.formatted.items = [
|
|
2253
2688
|
{
|
|
2254
2689
|
type: "network",
|
|
2690
|
+
code: "NETT",
|
|
2255
2691
|
label: "Network",
|
|
2256
2692
|
value: formattedNetwork
|
|
2257
2693
|
},
|
|
2258
2694
|
{
|
|
2259
2695
|
type: "version",
|
|
2696
|
+
code: "VER",
|
|
2260
2697
|
label: "Version",
|
|
2261
2698
|
value: decodeResult.raw.version
|
|
2262
2699
|
}
|
|
@@ -2265,6 +2702,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2265
2702
|
if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
|
|
2266
2703
|
decodeResult.formatted.items.push({
|
|
2267
2704
|
type: "ground_station",
|
|
2705
|
+
code: "GNDSTN",
|
|
2268
2706
|
label: "Ground Station",
|
|
2269
2707
|
value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
|
|
2270
2708
|
});
|
|
@@ -2272,6 +2710,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2272
2710
|
if (decodeResult.raw.groundStation.iataCode) {
|
|
2273
2711
|
decodeResult.formatted.items.push({
|
|
2274
2712
|
type: "iataCode",
|
|
2713
|
+
code: "IATA",
|
|
2275
2714
|
label: "IATA",
|
|
2276
2715
|
value: decodeResult.raw.groundStation.iataCode
|
|
2277
2716
|
});
|
|
@@ -2279,6 +2718,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2279
2718
|
if (decodeResult.raw.groundStation.icaoCode) {
|
|
2280
2719
|
decodeResult.formatted.items.push({
|
|
2281
2720
|
type: "icaoCode",
|
|
2721
|
+
code: "ICAO",
|
|
2282
2722
|
label: "ICAO",
|
|
2283
2723
|
value: decodeResult.raw.groundStation.icaoCode
|
|
2284
2724
|
});
|
|
@@ -2286,6 +2726,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2286
2726
|
if (decodeResult.raw.groundStation.coordinates.latitude) {
|
|
2287
2727
|
decodeResult.formatted.items.push({
|
|
2288
2728
|
type: "coordinates",
|
|
2729
|
+
code: "COORD",
|
|
2289
2730
|
label: "Ground Station Location",
|
|
2290
2731
|
value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
|
|
2291
2732
|
});
|
|
@@ -2293,6 +2734,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2293
2734
|
if (decodeResult.raw.groundStation.airport) {
|
|
2294
2735
|
decodeResult.formatted.items.push({
|
|
2295
2736
|
type: "airport",
|
|
2737
|
+
code: "APT",
|
|
2296
2738
|
label: "Airport",
|
|
2297
2739
|
value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
|
|
2298
2740
|
});
|
|
@@ -2301,6 +2743,7 @@ var Label_SQ = class extends DecoderPlugin {
|
|
|
2301
2743
|
if (decodeResult.raw.vdlFrequency) {
|
|
2302
2744
|
decodeResult.formatted.items.push({
|
|
2303
2745
|
type: "vdlFrequency",
|
|
2746
|
+
code: "VDLFRQ",
|
|
2304
2747
|
label: "VDL Frequency",
|
|
2305
2748
|
value: `${decodeResult.raw.vdlFrequency} MHz`
|
|
2306
2749
|
});
|
|
@@ -2457,31 +2900,48 @@ var Label_QQ = class extends DecoderPlugin {
|
|
|
2457
2900
|
decode(message, options = {}) {
|
|
2458
2901
|
const decodeResult = this.defaultResult();
|
|
2459
2902
|
decodeResult.decoder.name = this.name;
|
|
2460
|
-
decodeResult.
|
|
2461
|
-
decodeResult.raw.destination = message.text.substring(4, 8);
|
|
2462
|
-
decodeResult.raw.wheels_off = message.text.substring(8, 12);
|
|
2463
|
-
decodeResult.remaining.text = message.text.substring(12);
|
|
2903
|
+
decodeResult.message = message;
|
|
2464
2904
|
decodeResult.formatted.description = "OFF Report";
|
|
2465
|
-
decodeResult.
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2905
|
+
ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
|
|
2906
|
+
ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
|
|
2907
|
+
decodeResult.raw.wheels_off = message.text.substring(8, 12);
|
|
2908
|
+
if (message.text.substring(12, 19) === "\r\n001FE") {
|
|
2909
|
+
decodeResult.raw.day_of_month = message.text.substring(19, 21);
|
|
2910
|
+
decodeResult.raw.wheels_off = message.text.substring(21, 27);
|
|
2911
|
+
let latdir = message.text.substring(27, 28);
|
|
2912
|
+
let latdeg = Number(message.text.substring(28, 30));
|
|
2913
|
+
let latmin = Number(message.text.substring(30, 34));
|
|
2914
|
+
let londir = message.text.substring(34, 35);
|
|
2915
|
+
let londeg = Number(message.text.substring(35, 38));
|
|
2916
|
+
let lonmin = Number(message.text.substring(38, 42));
|
|
2917
|
+
decodeResult.raw.position = {
|
|
2918
|
+
latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
|
|
2919
|
+
longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
|
|
2920
|
+
};
|
|
2921
|
+
decodeResult.remaining.text = message.text.substring(42, 45);
|
|
2922
|
+
if (decodeResult.remaining.text !== "---") {
|
|
2923
|
+
ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
|
|
2924
|
+
} else {
|
|
2925
|
+
ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
|
|
2483
2926
|
}
|
|
2484
|
-
|
|
2927
|
+
ResultFormatter.unknown(decodeResult, message.text.substring(48));
|
|
2928
|
+
} else {
|
|
2929
|
+
decodeResult.remaining.text = message.text.substring(12);
|
|
2930
|
+
}
|
|
2931
|
+
decodeResult.formatted.items.push({
|
|
2932
|
+
type: "wheels_off",
|
|
2933
|
+
code: "WOFF",
|
|
2934
|
+
label: "Wheels OFF",
|
|
2935
|
+
value: decodeResult.raw.wheels_off
|
|
2936
|
+
});
|
|
2937
|
+
if (decodeResult.raw.position) {
|
|
2938
|
+
decodeResult.formatted.items.push({
|
|
2939
|
+
type: "aircraft_position",
|
|
2940
|
+
code: "POS",
|
|
2941
|
+
label: "Aircraft Position",
|
|
2942
|
+
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
2943
|
+
});
|
|
2944
|
+
}
|
|
2485
2945
|
decodeResult.decoded = true;
|
|
2486
2946
|
if (decodeResult.remaining.text === "")
|
|
2487
2947
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -3304,7 +3764,11 @@ var MessageDecoder = class {
|
|
|
3304
3764
|
this.debug = false;
|
|
3305
3765
|
this.registerPlugin(new Label_ColonComma(this));
|
|
3306
3766
|
this.registerPlugin(new Label_5Z(this));
|
|
3767
|
+
this.registerPlugin(new Label_10_LDR(this));
|
|
3768
|
+
this.registerPlugin(new Label_10_POS(this));
|
|
3769
|
+
this.registerPlugin(new Label_10_Slash(this));
|
|
3307
3770
|
this.registerPlugin(new Label_12_N_Space(this));
|
|
3771
|
+
this.registerPlugin(new Label_13Through18_Slash(this));
|
|
3308
3772
|
this.registerPlugin(new Label_15(this));
|
|
3309
3773
|
this.registerPlugin(new Label_15_FST(this));
|
|
3310
3774
|
this.registerPlugin(new Label_16_N_Space(this));
|
|
@@ -3316,6 +3780,7 @@ var MessageDecoder = class {
|
|
|
3316
3780
|
this.registerPlugin(new Label_44_OFF(this));
|
|
3317
3781
|
this.registerPlugin(new Label_44_ON(this));
|
|
3318
3782
|
this.registerPlugin(new Label_44_POS(this));
|
|
3783
|
+
this.registerPlugin(new Label_4N(this));
|
|
3319
3784
|
this.registerPlugin(new Label_B6_Forwardslash(this));
|
|
3320
3785
|
this.registerPlugin(new Label_H1_FPN(this));
|
|
3321
3786
|
this.registerPlugin(new Label_H1_FLR(this));
|
|
@@ -3324,7 +3789,9 @@ var MessageDecoder = class {
|
|
|
3324
3789
|
this.registerPlugin(new Label_H1_OHMA(this));
|
|
3325
3790
|
this.registerPlugin(new Label_H1_POS(this));
|
|
3326
3791
|
this.registerPlugin(new Label_H1_WRN(this));
|
|
3792
|
+
this.registerPlugin(new Label_HX(this));
|
|
3327
3793
|
this.registerPlugin(new Label_80(this));
|
|
3794
|
+
this.registerPlugin(new Label_83(this));
|
|
3328
3795
|
this.registerPlugin(new Label_8E(this));
|
|
3329
3796
|
this.registerPlugin(new Label_1M_Slash(this));
|
|
3330
3797
|
this.registerPlugin(new Label_SQ(this));
|