@airframes/acars-decoder 1.4.3 → 1.4.5
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/DateTimeUtils.d.ts +8 -0
- package/dist/DateTimeUtils.js +27 -0
- package/dist/DecoderPlugin.d.ts +3 -1
- package/dist/DecoderPlugin.js +3 -1
- package/dist/IcaoDecoder.d.ts +3 -1
- package/dist/IcaoDecoder.js +3 -1
- package/dist/MessageDecoder.d.ts +3 -1
- package/dist/MessageDecoder.js +5 -1
- package/dist/bin/acars-decoder-test.js +9 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +20 -0
- package/dist/plugins/Label_16_N_Space.d.ts +11 -0
- package/dist/plugins/Label_16_N_Space.js +80 -0
- package/dist/plugins/Label_16_N_Space.test.d.ts +1 -0
- package/dist/plugins/Label_16_N_Space.test.js +84 -0
- package/dist/plugins/Label_1M_Slash.js +2 -4
- package/dist/plugins/Label_1M_Slash.test.js +3 -3
- package/dist/plugins/Label_30_Slash_EA.d.ts +11 -0
- package/dist/plugins/Label_30_Slash_EA.js +54 -0
- package/dist/plugins/Label_30_Slash_EA.test.d.ts +1 -0
- package/dist/plugins/Label_30_Slash_EA.test.js +35 -0
- package/dist/plugins/Label_8E.js +2 -9
- package/dist/plugins/Label_8E.test.js +3 -3
- package/dist/plugins/official.d.ts +2 -0
- package/dist/plugins/official.js +2 -0
- package/package.json +12 -3
- package/src/DateTimeUtils.ts +26 -0
- package/src/DecoderPlugin.ts +83 -0
- package/src/DecoderPluginInterface.ts +9 -0
- package/src/IcaoDecoder.ts +137 -0
- package/src/MessageDecoder.ts +117 -0
- package/src/bin/acars-decoder-test.ts +67 -0
- package/src/bin/acars-decoder.ts +23 -0
- package/src/index.d.ts +15 -0
- package/src/index.ts +4 -0
- package/src/plugins/Label_15.ts +45 -0
- package/src/plugins/Label_16_N_Space.test.ts +94 -0
- package/src/plugins/Label_16_N_Space.ts +91 -0
- package/src/plugins/Label_1M_Slash.test.ts +45 -0
- package/src/plugins/Label_1M_Slash.ts +69 -0
- package/src/plugins/Label_20_CFB.01.ts +81 -0
- package/src/plugins/Label_20_POS.ts +68 -0
- package/src/plugins/Label_30_Slash_EA.test.ts +37 -0
- package/src/plugins/Label_30_Slash_EA.ts +60 -0
- package/src/plugins/Label_44_ETA.ts +81 -0
- package/src/plugins/Label_44_IN.ts +81 -0
- package/src/plugins/Label_44_OFF.ts +88 -0
- package/src/plugins/Label_44_ON.ts +81 -0
- package/src/plugins/Label_44_POS.ts +96 -0
- package/src/plugins/Label_5Z.ts +125 -0
- package/src/plugins/Label_80.ts +215 -0
- package/src/plugins/Label_8E.test.ts +34 -0
- package/src/plugins/Label_8E.ts +55 -0
- package/src/plugins/Label_B6.ts +28 -0
- package/src/plugins/Label_ColonComma.ts +32 -0
- package/src/plugins/Label_H1.ts +18 -0
- package/src/plugins/Label_H1_M1BPOS.ts +60 -0
- package/src/plugins/Label_H1_M1BPRG.ts +40 -0
- package/src/plugins/Label_QP.ts +54 -0
- package/src/plugins/Label_QQ.ts +54 -0
- package/src/plugins/Label_QR.ts +54 -0
- package/src/plugins/Label_QS.ts +54 -0
- package/src/plugins/Label_SQ.ts +111 -0
- package/src/plugins/official.ts +22 -0
- package/tsconfig.json +2 -3
- package/index.d.ts +0 -17
- package/index.ts +0 -4
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
// On Runway Report
|
|
4
|
+
export class Label_44_ON extends DecoderPlugin {
|
|
5
|
+
name = 'label-44-on';
|
|
6
|
+
|
|
7
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
8
|
+
return {
|
|
9
|
+
labels: ['44'],
|
|
10
|
+
preambles: ['00ON01', '00ON02', '00ON03', 'ON01', 'ON02', 'ON03'],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
decode(message: any, options: any = {}) : any {
|
|
15
|
+
const decodeResult: any = this.defaultResult;
|
|
16
|
+
decodeResult.decoder.name = this.name;
|
|
17
|
+
decodeResult.formatted.description = 'On Runway Report';
|
|
18
|
+
decodeResult.message = message;
|
|
19
|
+
|
|
20
|
+
// Style: ON02,N38333W121178,KRNO,KMHR,0806,2350,005.2
|
|
21
|
+
// Match: ON02,coords,departure_icao,arrival_icao,current_date,current_time,fuel_in_tons
|
|
22
|
+
const regex = /^ON02,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
|
|
23
|
+
const results = message.text.match(regex);
|
|
24
|
+
if (results) {
|
|
25
|
+
if (options.debug) {
|
|
26
|
+
console.log(`Label 44 On Runway Report: groups`);
|
|
27
|
+
console.log(results.groups);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const coordsRegex = /(?<lac>[NS])(?<la>.+)\s*(?<lnc>[EW])(?<ln>.+)/;
|
|
31
|
+
const coordsResults = results.groups.unsplit_coords.match(coordsRegex);
|
|
32
|
+
|
|
33
|
+
decodeResult.raw.latitude_direction = coordsResults.groups.lac;
|
|
34
|
+
decodeResult.raw.latitude = Number(coordsResults.groups.la) / 1000;
|
|
35
|
+
decodeResult.raw.longitude_direction = coordsResults.groups.lnc;
|
|
36
|
+
decodeResult.raw.longitude = Number(coordsResults.groups.ln) / 1000;
|
|
37
|
+
decodeResult.raw.departure_icao = results.groups.departure_icao;
|
|
38
|
+
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
39
|
+
decodeResult.raw.current_time = Date.parse(
|
|
40
|
+
new Date().getFullYear() + "-" +
|
|
41
|
+
results.groups.current_date.substr(0, 2) + "-" +
|
|
42
|
+
results.groups.current_date.substr(2, 2) + "T" +
|
|
43
|
+
results.groups.current_time.substr(0, 2) + ":" +
|
|
44
|
+
results.groups.current_time.substr(2, 2) + ":00Z"
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (results.groups.fuel_in_tons != '***' && results.groups.fuel_in_tons != '****') {
|
|
48
|
+
decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
decodeResult.formatted.items.push({
|
|
52
|
+
type: 'aircraft_position',
|
|
53
|
+
code: 'POS',
|
|
54
|
+
label: 'Aircraft Position',
|
|
55
|
+
value: `${decodeResult.raw.latitude} ${decodeResult.raw.latitude_direction}, ${decodeResult.raw.longitude} ${decodeResult.raw.longitude_direction}`,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
decodeResult.formatted.items.push({
|
|
59
|
+
type: 'origin',
|
|
60
|
+
code: 'ORG',
|
|
61
|
+
label: 'Origin',
|
|
62
|
+
value: decodeResult.raw.departure_icao,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
decodeResult.formatted.items.push({
|
|
66
|
+
type: 'destination',
|
|
67
|
+
code: 'DST',
|
|
68
|
+
label: 'Destination',
|
|
69
|
+
value: decodeResult.raw.arrival_icao,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
decodeResult.decoded = true;
|
|
75
|
+
decodeResult.decoder.decodeLevel = 'full';
|
|
76
|
+
|
|
77
|
+
return decodeResult;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
// General Aviation Position Report
|
|
4
|
+
export class Label_44_POS extends DecoderPlugin {
|
|
5
|
+
name = 'label-44-pos';
|
|
6
|
+
|
|
7
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
8
|
+
return {
|
|
9
|
+
labels: ['44'],
|
|
10
|
+
preambles: ['00POS01', '00POS02', '00POS03', 'POS01', 'POS02', 'POS03'],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
decode(message: any, options: any = {}) : any {
|
|
15
|
+
const decodeResult: any = this.defaultResult;
|
|
16
|
+
decodeResult.decoder.name = this.name;
|
|
17
|
+
decodeResult.formatted.description = 'Position Report';
|
|
18
|
+
decodeResult.message = message;
|
|
19
|
+
|
|
20
|
+
// Style: POS02,N38338W121179,GRD,KMHR,KPDX,0807,0003,0112,005.1
|
|
21
|
+
// Match: POS02,coords,flight_level_or_ground,departure_icao,arrival_icao,current_date,current_time,eta_time,unknown
|
|
22
|
+
const regex = /^POS02,(?<unsplit_coords>.*),(?<flight_level_or_ground>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
|
|
23
|
+
const results = message.text.match(regex);
|
|
24
|
+
if (results) {
|
|
25
|
+
if (options.debug) {
|
|
26
|
+
console.log(`Label 44 Position Report: groups`);
|
|
27
|
+
console.log(results.groups);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const coordsRegex = /(?<lac>[NS])(?<la>.+)\s*(?<lnc>[EW])(?<ln>.+)/;
|
|
31
|
+
const coordsResults = results.groups.unsplit_coords.match(coordsRegex);
|
|
32
|
+
|
|
33
|
+
decodeResult.raw.latitude_direction = coordsResults.groups.lac;
|
|
34
|
+
decodeResult.raw.latitude = Number(coordsResults.groups.la) / 1000;
|
|
35
|
+
decodeResult.raw.longitude_direction = coordsResults.groups.lnc;
|
|
36
|
+
decodeResult.raw.longitude = Number(coordsResults.groups.ln) / 1000;
|
|
37
|
+
decodeResult.raw.flight_level = results.groups.flight_level_or_ground == 'GRD' || results.groups.flight_level_or_ground == '***' ? '0' : Number(results.groups.flight_level_or_ground);
|
|
38
|
+
decodeResult.raw.departure_icao = results.groups.departure_icao;
|
|
39
|
+
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
40
|
+
decodeResult.raw.current_time = Date.parse(
|
|
41
|
+
new Date().getFullYear() + "-" +
|
|
42
|
+
results.groups.current_date.substr(0, 2) + "-" +
|
|
43
|
+
results.groups.current_date.substr(2, 2) + "T" +
|
|
44
|
+
results.groups.current_time.substr(0, 2) + ":" +
|
|
45
|
+
results.groups.current_time.substr(2, 2) + ":00Z"
|
|
46
|
+
);
|
|
47
|
+
decodeResult.raw.eta_time = Date.parse(
|
|
48
|
+
new Date().getFullYear() + "-" +
|
|
49
|
+
results.groups.current_date.substr(0, 2) + "-" +
|
|
50
|
+
results.groups.current_date.substr(2, 2) + "T" +
|
|
51
|
+
results.groups.eta_time.substr(0, 2) + ":" +
|
|
52
|
+
results.groups.eta_time.substr(2, 2) + ":00Z"
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (results.groups.fuel_in_tons != '***' && results.groups.fuel_in_tons != '****') {
|
|
56
|
+
decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
decodeResult.formatted.items.push({
|
|
60
|
+
type: 'aircraft_position',
|
|
61
|
+
code: 'POS',
|
|
62
|
+
label: 'Aircraft Position',
|
|
63
|
+
value: `${decodeResult.raw.latitude} ${decodeResult.raw.latitude_direction}, ${decodeResult.raw.longitude} ${decodeResult.raw.longitude_direction}`,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
decodeResult.formatted.items.push({
|
|
67
|
+
type: 'origin',
|
|
68
|
+
code: 'ORG',
|
|
69
|
+
label: 'Origin',
|
|
70
|
+
value: decodeResult.raw.departure_icao,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
decodeResult.formatted.items.push({
|
|
74
|
+
type: 'destination',
|
|
75
|
+
code: 'DST',
|
|
76
|
+
label: 'Destination',
|
|
77
|
+
value: decodeResult.raw.arrival_icao,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
decodeResult.formatted.items.push({
|
|
81
|
+
type: 'flight_level',
|
|
82
|
+
code: 'FL',
|
|
83
|
+
label: 'Flight Level',
|
|
84
|
+
value: decodeResult.raw.flight_level,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
decodeResult.decoded = true;
|
|
90
|
+
decodeResult.decoder.decodeLevel = 'full';
|
|
91
|
+
|
|
92
|
+
return decodeResult;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export default {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
export class Label_5Z extends DecoderPlugin {
|
|
4
|
+
name = 'label-5z';
|
|
5
|
+
|
|
6
|
+
descriptions: any = {
|
|
7
|
+
B1: 'Request Weight and Balance',
|
|
8
|
+
B3: 'Request Departure Clearance',
|
|
9
|
+
CD: 'Weight and Balance',
|
|
10
|
+
CG: 'Request Pre-departure clearance, PDC',
|
|
11
|
+
CM: 'Crew Scheduling',
|
|
12
|
+
C3: 'Off Message',
|
|
13
|
+
C4: 'Flight Dispatch',
|
|
14
|
+
C5: 'Maintenance Message',
|
|
15
|
+
C6: 'Customer Service',
|
|
16
|
+
10: 'PIREP',
|
|
17
|
+
C11: 'International PIREP',
|
|
18
|
+
DS: 'Late Message',
|
|
19
|
+
D3: 'Holding Pattern Message',
|
|
20
|
+
D6: 'From-To + Date',
|
|
21
|
+
D7: 'From-To + Alternate + Time',
|
|
22
|
+
EO: 'In Range',
|
|
23
|
+
PW: 'Position Weather',
|
|
24
|
+
RL: 'Request Release',
|
|
25
|
+
R3: 'Request HOWGOZIT Message',
|
|
26
|
+
R4: 'Request the Latest POSBD',
|
|
27
|
+
TC: 'From-To Fuel',
|
|
28
|
+
WB: 'From-To',
|
|
29
|
+
W1: 'Request Weather for City',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
33
|
+
return {
|
|
34
|
+
labels: ['5Z'],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
decode(message: any, options: any = {}) : any {
|
|
39
|
+
const decodeResult: any = this.defaultResult;
|
|
40
|
+
decodeResult.decoder.name = this.name;
|
|
41
|
+
|
|
42
|
+
decodeResult.formatted.description = 'Airline Designated Downlink';
|
|
43
|
+
|
|
44
|
+
const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
|
|
45
|
+
let results = message.text.match(uaRegex);
|
|
46
|
+
|
|
47
|
+
if (results && results.length >= 2) {
|
|
48
|
+
// Successful match: United Airlines 5Z message
|
|
49
|
+
const type : string = results.groups.type.split('/')[0];
|
|
50
|
+
const { remainder } = results.groups;
|
|
51
|
+
// console.log(results);
|
|
52
|
+
// console.log(`DECODER: Matched 'United Airlines 5Z': type = ${type}, remainder = ${remainder}`);
|
|
53
|
+
|
|
54
|
+
const typeDescription: string = this.descriptions[type] ? this.descriptions[type] : 'Unknown';
|
|
55
|
+
decodeResult.raw.airline = 'United Airlines';
|
|
56
|
+
decodeResult.formatted.items.push({
|
|
57
|
+
type: 'airline',
|
|
58
|
+
label: 'Airline',
|
|
59
|
+
value: 'United Airlines',
|
|
60
|
+
});
|
|
61
|
+
decodeResult.raw.message_type = type;
|
|
62
|
+
decodeResult.formatted.items.push({
|
|
63
|
+
type: 'message_type',
|
|
64
|
+
label: 'Message Type',
|
|
65
|
+
value: `${typeDescription} (${type})`,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (type === 'B3') {
|
|
69
|
+
const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/; // eslint-disable-line max-len
|
|
70
|
+
results = remainder.match(rdcRegex);
|
|
71
|
+
|
|
72
|
+
if (results) {
|
|
73
|
+
decodeResult.raw.origin = results.groups.from;
|
|
74
|
+
decodeResult.formatted.items.push({
|
|
75
|
+
type: 'origin',
|
|
76
|
+
label: 'Origin',
|
|
77
|
+
value: `${results.groups.from}`,
|
|
78
|
+
});
|
|
79
|
+
decodeResult.raw.destination = results.groups.to;
|
|
80
|
+
decodeResult.formatted.items.push({
|
|
81
|
+
type: 'destination',
|
|
82
|
+
label: 'Destination',
|
|
83
|
+
value: `${results.groups.to}`,
|
|
84
|
+
});
|
|
85
|
+
decodeResult.formatted.items.push({
|
|
86
|
+
type: 'unknown1',
|
|
87
|
+
label: 'Unknown Field 1',
|
|
88
|
+
value: `${results.groups.unknown1}`,
|
|
89
|
+
});
|
|
90
|
+
decodeResult.raw.runway = results.groups.runway;
|
|
91
|
+
decodeResult.formatted.items.push({
|
|
92
|
+
type: 'runway',
|
|
93
|
+
label: 'Runway',
|
|
94
|
+
value: `${results.groups.runway}`,
|
|
95
|
+
});
|
|
96
|
+
decodeResult.formatted.items.push({
|
|
97
|
+
type: 'unknown2',
|
|
98
|
+
label: 'Unknown Field 2',
|
|
99
|
+
value: `${results.groups.unknown2}`,
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
if (options.debug) {
|
|
103
|
+
console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
decodeResult.remaining.text = remainder;
|
|
108
|
+
}
|
|
109
|
+
decodeResult.decoded = true;
|
|
110
|
+
decodeResult.decoder.decodeLevel = 'partial';
|
|
111
|
+
} else {
|
|
112
|
+
// Unknown
|
|
113
|
+
if (options.debug) {
|
|
114
|
+
console.log(`Decoder: Unknown 5Z message: ${message.text}`);
|
|
115
|
+
}
|
|
116
|
+
decodeResult.remaining.text = message.text;
|
|
117
|
+
decodeResult.decoded = false;
|
|
118
|
+
decodeResult.decoder.decodeLevel = 'none';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return decodeResult;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default {};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
// Airline Defined
|
|
4
|
+
// 3N01 POSRPT
|
|
5
|
+
export class Label_80 extends DecoderPlugin {
|
|
6
|
+
name = 'label-80';
|
|
7
|
+
|
|
8
|
+
descriptions: any = {
|
|
9
|
+
ALT: 'Altitude',
|
|
10
|
+
DWND: 'Wind Direction',
|
|
11
|
+
ETA: 'Estimated Time of Arrival',
|
|
12
|
+
FOB: 'Fuel on Board',
|
|
13
|
+
FL: 'Flight Level',
|
|
14
|
+
HDG: 'Heading',
|
|
15
|
+
MCH: 'Aircraft Speed',
|
|
16
|
+
NWYP: 'Next Waypoint',
|
|
17
|
+
POS: 'Aircraft Position',
|
|
18
|
+
SAT: 'Static Air Temperature',
|
|
19
|
+
SWND: 'Window Speed',
|
|
20
|
+
TAS: 'True Airspeed',
|
|
21
|
+
WYP: 'Waypoint',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
25
|
+
return {
|
|
26
|
+
labels: ['80'],
|
|
27
|
+
preambles: ['3N01 POSRPT'],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
decode(message: any, options: any = {}) : any {
|
|
32
|
+
const decodeResult: any = this.defaultResult;
|
|
33
|
+
decodeResult.decoder.name = this.name;
|
|
34
|
+
|
|
35
|
+
decodeResult.formatted.description = 'Airline Defined Position Report';
|
|
36
|
+
|
|
37
|
+
const parts = message.text.split('\n');
|
|
38
|
+
|
|
39
|
+
let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/; // eslint-disable-line max-len
|
|
40
|
+
let results = parts[0].match(posRptRegex);
|
|
41
|
+
if (results && results.length > 0) {
|
|
42
|
+
decodeResult.raw.origin = results.groups.orig;
|
|
43
|
+
decodeResult.formatted.items.push({
|
|
44
|
+
type: 'origin',
|
|
45
|
+
code: 'ORG',
|
|
46
|
+
label: 'Origin',
|
|
47
|
+
value: `${results.groups.orig}`,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
decodeResult.raw.destination = results.groups.dest;
|
|
51
|
+
decodeResult.formatted.items.push({
|
|
52
|
+
type: 'destination',
|
|
53
|
+
code: 'DST',
|
|
54
|
+
label: 'Destination',
|
|
55
|
+
value: `${results.groups.dest}`,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
decodeResult.raw.tail = results.groups.tail;
|
|
59
|
+
decodeResult.formatted.items.push({
|
|
60
|
+
type: 'tail',
|
|
61
|
+
label: 'Tail',
|
|
62
|
+
value: `${results.groups.tail}`,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (results.groups.agate) {
|
|
66
|
+
decodeResult.raw.arrival_gate = results.groups.agate;
|
|
67
|
+
decodeResult.formatted.items.push({
|
|
68
|
+
type: 'arrival_gate',
|
|
69
|
+
code: 'ARG',
|
|
70
|
+
label: 'Arrival Gate',
|
|
71
|
+
value: `${results.groups.agate}`,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
decodeResult.raw.scheduled_time_of_arrival = results.groups.sta
|
|
75
|
+
decodeResult.formatted.items.push({
|
|
76
|
+
type: 'scheduled_time_of_arrival',
|
|
77
|
+
code: 'STA',
|
|
78
|
+
label: 'Scheduled Time of Arrival',
|
|
79
|
+
value: `${results.groups.sta}`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi; // eslint-disable-line no-useless-escape
|
|
84
|
+
// console.log('Regex:', posRptRegex);
|
|
85
|
+
const remainingParts = parts.slice(1);
|
|
86
|
+
// console.log("Remaining Parts:", remainingParts);
|
|
87
|
+
|
|
88
|
+
for (const part of remainingParts) { // eslint-disable-line no-restricted-syntax
|
|
89
|
+
// console.log('Part:', part);
|
|
90
|
+
const matches = part.matchAll(posRptRegex);
|
|
91
|
+
// console.log('Matches:', matches);
|
|
92
|
+
for (const match of matches) { // eslint-disable-line no-restricted-syntax
|
|
93
|
+
// console.log('Match:', match);
|
|
94
|
+
switch (match.groups.field) {
|
|
95
|
+
case 'ALT': {
|
|
96
|
+
decodeResult.raw.altitude = match.groups.value;
|
|
97
|
+
decodeResult.formatted.items.push({
|
|
98
|
+
type: 'altitude',
|
|
99
|
+
code: 'ALT',
|
|
100
|
+
label: this.descriptions[match.groups.field],
|
|
101
|
+
value: `${decodeResult.raw.altitude} feet`,
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case 'DWND': {
|
|
106
|
+
decodeResult.raw.wind_direction = Number(match.groups.value);
|
|
107
|
+
decodeResult.formatted.items.push({
|
|
108
|
+
type: 'wind_direction',
|
|
109
|
+
code: 'DWND',
|
|
110
|
+
label: this.descriptions[match.groups.field],
|
|
111
|
+
value: decodeResult.raw.wind_direction,
|
|
112
|
+
});
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case 'FL': {
|
|
116
|
+
decodeResult.raw.flight_level = match.groups.value;
|
|
117
|
+
decodeResult.formatted.items.push({
|
|
118
|
+
type: 'flight_level',
|
|
119
|
+
code: 'FL',
|
|
120
|
+
label: this.descriptions[match.groups.field],
|
|
121
|
+
value: decodeResult.raw.flight_level,
|
|
122
|
+
});
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'FOB': {
|
|
126
|
+
decodeResult.raw.fuel_on_board = match.groups.value;
|
|
127
|
+
decodeResult.formatted.items.push({
|
|
128
|
+
type: 'fuel_on_board',
|
|
129
|
+
code: 'FOB',
|
|
130
|
+
label: this.descriptions[match.groups.field],
|
|
131
|
+
value: decodeResult.raw.fuel_on_board,
|
|
132
|
+
});
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'HDG': {
|
|
136
|
+
decodeResult.raw.heading = Number(match.groups.value);
|
|
137
|
+
decodeResult.formatted.items.push({
|
|
138
|
+
type: 'heading',
|
|
139
|
+
code: 'HDG',
|
|
140
|
+
label: this.descriptions[match.groups.field],
|
|
141
|
+
value: decodeResult.raw.heading,
|
|
142
|
+
});
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case 'MCH': {
|
|
146
|
+
decodeResult.raw.mach = match.groups.value / 1000;
|
|
147
|
+
decodeResult.formatted.items.push({
|
|
148
|
+
type: 'mach',
|
|
149
|
+
code: 'MCH',
|
|
150
|
+
label: this.descriptions[match.groups.field],
|
|
151
|
+
value: `${decodeResult.raw.mach} Mach`,
|
|
152
|
+
});
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case 'NWYP': {
|
|
156
|
+
decodeResult.raw.next_waypoint = match.groups.value;
|
|
157
|
+
decodeResult.formatted.items.push({
|
|
158
|
+
type: 'next_waypoint',
|
|
159
|
+
code: 'NWYP',
|
|
160
|
+
label: this.descriptions[match.groups.field],
|
|
161
|
+
value: decodeResult.raw.next_waypoint,
|
|
162
|
+
});
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 'POS': {
|
|
166
|
+
const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
|
|
167
|
+
const posResult = match.groups.value.match(posRegex);
|
|
168
|
+
const latitude = (Number(posResult.groups.lat) / 100) * (posResult.groups.lngd === 'S' ? -1 : 1);
|
|
169
|
+
const longitude = (Number(posResult.groups.lng) / 100) * (posResult.groups.lngd === 'W' ? -1 : 1);
|
|
170
|
+
decodeResult.raw.aircraft_position = {
|
|
171
|
+
latitude,
|
|
172
|
+
longitude,
|
|
173
|
+
};
|
|
174
|
+
decodeResult.formatted.items.push({
|
|
175
|
+
type: 'aircraft_position',
|
|
176
|
+
code: 'POS',
|
|
177
|
+
label: this.descriptions[match.groups.field],
|
|
178
|
+
value: `${(Number(posResult.groups.lat) / 100).toPrecision(5)} ${posResult.groups.latd}, ${(Number(posResult.groups.lng) / 100).toPrecision(5)} ${posResult.groups.lngd}`,
|
|
179
|
+
});
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case 'SWND': {
|
|
183
|
+
decodeResult.raw.wind_speed = Number(match.groups.value);
|
|
184
|
+
decodeResult.formatted.items.push({
|
|
185
|
+
type: 'wind_speed',
|
|
186
|
+
code: 'SWND',
|
|
187
|
+
label: this.descriptions[match.groups.field],
|
|
188
|
+
value: decodeResult.raw.wind_speed,
|
|
189
|
+
});
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
default: {
|
|
193
|
+
if (match.groups.field != undefined) {
|
|
194
|
+
const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : 'Unknown';
|
|
195
|
+
decodeResult.formatted.items.push({
|
|
196
|
+
type: match.groups.field,
|
|
197
|
+
code: match.groups.field,
|
|
198
|
+
label: description || `Unknown (${match.groups.field})`,
|
|
199
|
+
value: `${match.groups.value}`,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
decodeResult.decoded = true;
|
|
208
|
+
decodeResult.decodeLevel = 'partial';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return decodeResult;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export default {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { MessageDecoder } from '../MessageDecoder';
|
|
2
|
+
import { Label_8E } from './Label_8E';
|
|
3
|
+
|
|
4
|
+
test('decodes Label 8E sample 1', () => {
|
|
5
|
+
const decoder = new MessageDecoder();
|
|
6
|
+
const decoderPlugin = new Label_8E(decoder);
|
|
7
|
+
|
|
8
|
+
expect(decoderPlugin.decode).toBeDefined();
|
|
9
|
+
expect(decoderPlugin.name).toBe('label-8e');
|
|
10
|
+
expect(decoderPlugin.qualifiers).toBeDefined();
|
|
11
|
+
expect(decoderPlugin.qualifiers()).toEqual({
|
|
12
|
+
labels: ['8E'],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const decodeResult = decoderPlugin.decode({ text: 'EGSS,1618' });
|
|
16
|
+
console.log(JSON.stringify(decodeResult, null, 2));
|
|
17
|
+
|
|
18
|
+
expect(decodeResult.decoded).toBe(true);
|
|
19
|
+
expect(decodeResult.decoder.name).toBe('label-8e');
|
|
20
|
+
expect(decodeResult.formatted.description).toBe('ETA Report');
|
|
21
|
+
expect(decodeResult.message.text).toBe('EGSS,1618');
|
|
22
|
+
expect(decodeResult.raw.arrival_icao).toBe('EGSS');
|
|
23
|
+
expect(decodeResult.formatted.items.length).toBe(2);
|
|
24
|
+
expect(decodeResult.formatted.items[0].type).toBe('eta');
|
|
25
|
+
expect(decodeResult.formatted.items[0].code).toBe('ETA');
|
|
26
|
+
expect(decodeResult.formatted.items[0].label).toBe('Estimated Time of Arrival');
|
|
27
|
+
// Check for the minutes as typescript doesn't have a UTC time string method
|
|
28
|
+
// so the hour will depend on the test host timezone.
|
|
29
|
+
expect((decodeResult.formatted.items[0].value as string).includes('18')).toBe(true);
|
|
30
|
+
expect(decodeResult.formatted.items[1].type).toBe('destination');
|
|
31
|
+
expect(decodeResult.formatted.items[1].code).toBe('DST');
|
|
32
|
+
expect(decodeResult.formatted.items[1].label).toBe('Destination');
|
|
33
|
+
expect(decodeResult.formatted.items[1].value).toBe('EGSS');
|
|
34
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { DateTimeUtils } from '../DateTimeUtils';
|
|
2
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
3
|
+
|
|
4
|
+
// ETA
|
|
5
|
+
export class Label_8E extends DecoderPlugin {
|
|
6
|
+
name = 'label-8e';
|
|
7
|
+
|
|
8
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
9
|
+
return {
|
|
10
|
+
labels: ["8E"],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
decode(message: any, options: any = {}) : any {
|
|
15
|
+
const decodeResult: any = this.defaultResult;
|
|
16
|
+
decodeResult.decoder.name = this.name;
|
|
17
|
+
decodeResult.formatted.description = 'ETA Report';
|
|
18
|
+
decodeResult.message = message;
|
|
19
|
+
|
|
20
|
+
// Style: EGSS,1618
|
|
21
|
+
// Match: arrival_icao,arrival_eta
|
|
22
|
+
const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
|
|
23
|
+
const results = message.text.match(regex);
|
|
24
|
+
if (results) {
|
|
25
|
+
if (options.debug) {
|
|
26
|
+
console.log(`Label 8E ETA: groups`);
|
|
27
|
+
console.log(results.groups);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
decodeResult.formatted.items.push({
|
|
31
|
+
type: 'eta',
|
|
32
|
+
code: 'ETA',
|
|
33
|
+
label: 'Estimated Time of Arrival',
|
|
34
|
+
value: DateTimeUtils.UTCToString(results.groups.arrival_eta),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
39
|
+
decodeResult.formatted.items.push({
|
|
40
|
+
type: 'destination',
|
|
41
|
+
code: 'DST',
|
|
42
|
+
label: 'Destination',
|
|
43
|
+
value: decodeResult.raw.arrival_icao,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
decodeResult.decoded = true;
|
|
49
|
+
decodeResult.decoder.decodeLevel = 'full';
|
|
50
|
+
|
|
51
|
+
return decodeResult;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
// CPDLC
|
|
4
|
+
export class Label_B6_Forwardslash extends DecoderPlugin {
|
|
5
|
+
name = 'label-b6-forwardslash';
|
|
6
|
+
|
|
7
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
8
|
+
return {
|
|
9
|
+
labels: ['B6'],
|
|
10
|
+
preambles: ['/'],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
decode(message: any, options: any = {}) : any {
|
|
15
|
+
const decodeResult: any = this.defaultResult;
|
|
16
|
+
decodeResult.decoder.name = this.name;
|
|
17
|
+
decodeResult.formatted.description = 'CPDLC Message';
|
|
18
|
+
decodeResult.message = message;
|
|
19
|
+
|
|
20
|
+
if (options.debug) {
|
|
21
|
+
console.log("CPDLC: " + message);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return decodeResult;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
export class Label_ColonComma extends DecoderPlugin {
|
|
4
|
+
name = 'label-colon-comma';
|
|
5
|
+
|
|
6
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
7
|
+
return {
|
|
8
|
+
labels: [':;'],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
decode(message: any, options: any = {}) : any {
|
|
13
|
+
const decodeResult: any = this.defaultResult;
|
|
14
|
+
decodeResult.decoder.name = this.name;
|
|
15
|
+
|
|
16
|
+
decodeResult.raw.frequency = Number(message.text) / 1000;
|
|
17
|
+
|
|
18
|
+
decodeResult.formatted.description = 'Aircraft Transceiver Frequency Change';
|
|
19
|
+
decodeResult.formatted.items.push({
|
|
20
|
+
type: 'frequency',
|
|
21
|
+
label: 'Frequency',
|
|
22
|
+
value: `${decodeResult.raw.frequency} MHz`,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
decodeResult.decoded = true;
|
|
26
|
+
decodeResult.decoder.decodeLevel = 'full';
|
|
27
|
+
|
|
28
|
+
return decodeResult;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DecoderPlugin } from '../DecoderPlugin';
|
|
2
|
+
|
|
3
|
+
export class Label_H1 extends DecoderPlugin {
|
|
4
|
+
qualifiers() { // eslint-disable-line class-methods-use-this
|
|
5
|
+
return {
|
|
6
|
+
labels: ['H1'],
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
decode(message: any, options: any = {}) : any {
|
|
11
|
+
const decodeResult: any = this.defaultResult;
|
|
12
|
+
// console.log('DECODER: H1 detected');
|
|
13
|
+
|
|
14
|
+
return decodeResult;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default {};
|