@aeroswarm/codec 0.1.11 → 0.1.13
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 +160 -62
- package/dist/surveillance/asterix/decoder.d.ts +7 -2
- package/dist/surveillance/asterix/decoder.d.ts.map +1 -1
- package/dist/surveillance/asterix/descriptor-fields.test.d.ts +2 -0
- package/dist/surveillance/asterix/descriptor-fields.test.d.ts.map +1 -0
- package/dist/surveillance/asterix/fields.d.ts.map +1 -1
- package/dist/surveillance/asterix/index.d.ts +2 -1
- package/dist/surveillance/asterix/index.d.ts.map +1 -1
- package/dist/surveillance/asterix/parser.d.ts +3 -1
- package/dist/surveillance/asterix/parser.d.ts.map +1 -1
- package/dist/surveillance/asterix/repetitive.test.d.ts +2 -0
- package/dist/surveillance/asterix/repetitive.test.d.ts.map +1 -0
- package/dist/surveillance/asterix/types.d.ts +19 -0
- package/dist/surveillance/asterix/types.d.ts.map +1 -1
- package/dist/surveillance/asterix/xml-loader.d.ts +2 -0
- package/dist/surveillance/asterix/xml-loader.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -87,7 +87,11 @@ function parseFormat(s) {
|
|
|
87
87
|
function parseVariable(s) {
|
|
88
88
|
const inner = firstContent(s, "Variable");
|
|
89
89
|
const m = inner.match(/<Fixed\s+length="(\d+)"/);
|
|
90
|
-
|
|
90
|
+
const chunks = [];
|
|
91
|
+
const re = /<Fixed\s+length="\d+"[^>]*>([\s\S]*?)<\/Fixed>/g;
|
|
92
|
+
let c;
|
|
93
|
+
while ((c = re.exec(inner)) !== null) chunks.push(parseBits(c[1]));
|
|
94
|
+
return { type: "variable", chunkBytes: m ? parseInt(m[1]) : 1, bits: chunks[0] ?? parseBits(firstContent(inner, "Fixed")), chunks };
|
|
91
95
|
}
|
|
92
96
|
function parseBits(s) {
|
|
93
97
|
const out = [];
|
|
@@ -116,11 +120,15 @@ function parseBits(s) {
|
|
|
116
120
|
}
|
|
117
121
|
return out;
|
|
118
122
|
}
|
|
123
|
+
function repetitionBytes(body, fallback) {
|
|
124
|
+
if (/<BDS[\s/>]/.test(body)) return 8;
|
|
125
|
+
const m = body.match(/<Fixed\s+length="(\d+)"/);
|
|
126
|
+
return m ? parseInt(m[1]) : fallback;
|
|
127
|
+
}
|
|
119
128
|
function parseRepetitive(s) {
|
|
120
129
|
const inner = firstContent(s, "Repetitive");
|
|
121
130
|
const repAttr = inner.match(/<Repetitive\s+rep="(\d+)"/);
|
|
122
|
-
|
|
123
|
-
return { type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: m ? parseInt(m[1]) : 0 };
|
|
131
|
+
return { type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: repetitionBytes(inner, 0) };
|
|
124
132
|
}
|
|
125
133
|
function parseCompound(s) {
|
|
126
134
|
const inner = firstContent(s, "Compound");
|
|
@@ -139,7 +147,7 @@ function parseCompound(s) {
|
|
|
139
147
|
subs.push({ type: "variable", chunkBytes: first ? parseInt(first[1]) : 1 });
|
|
140
148
|
} else if (child.tag === "Repetitive") {
|
|
141
149
|
const repAttr = child.open.match(/rep="(\d+)"/);
|
|
142
|
-
subs.push({ type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes:
|
|
150
|
+
subs.push({ type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: repetitionBytes(child.body, 1) });
|
|
143
151
|
} else {
|
|
144
152
|
subs.push({ type: "explicit" });
|
|
145
153
|
}
|
|
@@ -188,23 +196,23 @@ function parseFspec(buf, start = 0) {
|
|
|
188
196
|
return { bits, end: i };
|
|
189
197
|
}
|
|
190
198
|
function skipItem(buf, off, def) {
|
|
191
|
-
if (off >= buf.length) return buf.length;
|
|
199
|
+
if (off >= buf.length) return buf.length + 1;
|
|
192
200
|
switch (def.type) {
|
|
193
201
|
case "fixed":
|
|
194
|
-
return
|
|
202
|
+
return off + def.bytes;
|
|
195
203
|
case "variable": {
|
|
196
204
|
while (off + def.chunkBytes <= buf.length) {
|
|
197
205
|
const last = buf[off + def.chunkBytes - 1];
|
|
198
206
|
off += def.chunkBytes;
|
|
199
207
|
if ((last & 1) === 0) break;
|
|
200
208
|
}
|
|
201
|
-
return
|
|
209
|
+
return off;
|
|
202
210
|
}
|
|
203
211
|
case "repetitive": {
|
|
204
|
-
if (off + def.repBytes > buf.length) return buf.length;
|
|
212
|
+
if (off + def.repBytes > buf.length) return buf.length + 1;
|
|
205
213
|
let rep = 0;
|
|
206
214
|
for (let i = 0; i < def.repBytes; i++) rep = rep << 8 | buf[off + i];
|
|
207
|
-
return
|
|
215
|
+
return off + def.repBytes + rep * def.itemBytes;
|
|
208
216
|
}
|
|
209
217
|
case "compound": {
|
|
210
218
|
const presentIdxs = [];
|
|
@@ -222,13 +230,12 @@ function skipItem(buf, off, def) {
|
|
|
222
230
|
if (idx >= def.subs.length) break;
|
|
223
231
|
off = skipItem(buf, off, def.subs[idx]);
|
|
224
232
|
}
|
|
225
|
-
return
|
|
233
|
+
return off;
|
|
226
234
|
}
|
|
227
235
|
case "explicit": {
|
|
228
|
-
if (off >= buf.length) return
|
|
236
|
+
if (off >= buf.length) return buf.length + 1;
|
|
229
237
|
const len = buf[off];
|
|
230
|
-
off
|
|
231
|
-
return Math.min(off + len - 1, buf.length);
|
|
238
|
+
return off + Math.max(len, 1);
|
|
232
239
|
}
|
|
233
240
|
}
|
|
234
241
|
}
|
|
@@ -238,17 +245,18 @@ function decodeBlock(block, def, onField) {
|
|
|
238
245
|
const uapMap = new Map(def.uap.map((e) => [e.bit, e.id]));
|
|
239
246
|
for (let i = 0; i < bits.length; i++) {
|
|
240
247
|
if (!bits[i]) continue;
|
|
241
|
-
if (off >= block.length) return { end: block.length, complete: true };
|
|
248
|
+
if (off >= block.length) return { end: block.length, complete: true, overrun: true };
|
|
242
249
|
const uapPos = i + Math.floor(i / 7);
|
|
243
250
|
const id = uapMap.get(uapPos);
|
|
244
|
-
if (id === void 0) return { end: off, complete: false };
|
|
251
|
+
if (id === void 0) return { end: off, complete: false, overrun: false };
|
|
245
252
|
const itemDef = def.items.get(id);
|
|
246
|
-
if (!itemDef) return { end: off, complete: false };
|
|
253
|
+
if (!itemDef) return { end: off, complete: false, overrun: false };
|
|
247
254
|
const start = off;
|
|
248
255
|
off = skipItem(block, off, itemDef);
|
|
249
|
-
onField(id, block.slice(start, off), itemDef);
|
|
256
|
+
onField(id, block.slice(start, Math.min(off, block.length)), itemDef);
|
|
257
|
+
if (off > block.length) return { end: block.length, complete: true, overrun: true };
|
|
250
258
|
}
|
|
251
|
-
return { end: off, complete: true };
|
|
259
|
+
return { end: off, complete: true, overrun: false };
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
// src/surveillance/asterix/fields.ts
|
|
@@ -293,6 +301,60 @@ function trdFlags(raw, out) {
|
|
|
293
301
|
if (num(raw, "TST") === 1) out.testTarget = true;
|
|
294
302
|
if (num(raw, "RAB") === 1) out.fixedTransponder = true;
|
|
295
303
|
if (num(raw, "SIM") === 1) out.simulated = true;
|
|
304
|
+
const gbs = num(raw, "GBS");
|
|
305
|
+
if (gbs !== void 0) out.onGround = gbs === 1;
|
|
306
|
+
}
|
|
307
|
+
function compoundSubfields(d, sizeOf) {
|
|
308
|
+
const present = [];
|
|
309
|
+
let at = 0;
|
|
310
|
+
let sub = 0;
|
|
311
|
+
while (at < d.length) {
|
|
312
|
+
const b = d[at++];
|
|
313
|
+
for (let bit = 7; bit >= 1; bit--) {
|
|
314
|
+
if (b >> bit & 1) present.push(sub);
|
|
315
|
+
sub++;
|
|
316
|
+
}
|
|
317
|
+
if ((b & 1) === 0) break;
|
|
318
|
+
}
|
|
319
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
320
|
+
let off = at;
|
|
321
|
+
for (const index of present) {
|
|
322
|
+
const size = sizeOf(index, d, off);
|
|
323
|
+
if (size === void 0) break;
|
|
324
|
+
offsets.set(index, off);
|
|
325
|
+
off += size;
|
|
326
|
+
}
|
|
327
|
+
return offsets;
|
|
328
|
+
}
|
|
329
|
+
function derivedDataSize(index, d, off) {
|
|
330
|
+
if (index < 7) return [3, 6, 2, 2, 2, 2, 2][index];
|
|
331
|
+
if (index === 7) {
|
|
332
|
+
let n = 1;
|
|
333
|
+
while (off + n - 1 < d.length && (d[off + n - 1] & 1) === 1) n++;
|
|
334
|
+
return n;
|
|
335
|
+
}
|
|
336
|
+
if (index === 8) return off < d.length ? 1 + 15 * d[off] : void 0;
|
|
337
|
+
if (index === 9 || index === 10) return 2;
|
|
338
|
+
return void 0;
|
|
339
|
+
}
|
|
340
|
+
function flightPlanSize(index) {
|
|
341
|
+
return [2, 7, 4, 1, 4, 1, 4, 4][index];
|
|
342
|
+
}
|
|
343
|
+
function asciiAt(d, off, len) {
|
|
344
|
+
if (off === void 0 || d.length < off + len) return void 0;
|
|
345
|
+
const text = d.subarray(off, off + len).toString("latin1").trim();
|
|
346
|
+
return text.length > 0 && /^[A-Z0-9 ]+$/.test(text) ? text : void 0;
|
|
347
|
+
}
|
|
348
|
+
function targetSize(raw, out) {
|
|
349
|
+
const lengthM = num(raw, "Len", "Length");
|
|
350
|
+
const widthM = num(raw, "WIDTH", "Width");
|
|
351
|
+
const orientationDeg = num(raw, "ORI", "Ori");
|
|
352
|
+
if (lengthM === void 0 && widthM === void 0 && orientationDeg === void 0) return;
|
|
353
|
+
out.targetSize = {
|
|
354
|
+
...lengthM !== void 0 && { lengthM },
|
|
355
|
+
...widthM !== void 0 && { widthM },
|
|
356
|
+
...orientationDeg !== void 0 && { orientationDeg }
|
|
357
|
+
};
|
|
296
358
|
}
|
|
297
359
|
function decodeKnownField(cat, id, data, out, raw = {}) {
|
|
298
360
|
try {
|
|
@@ -329,6 +391,21 @@ function cat021(id, d, out, raw) {
|
|
|
329
391
|
trdFlags(raw, out);
|
|
330
392
|
break;
|
|
331
393
|
// I021/040 TRD
|
|
394
|
+
case "020": {
|
|
395
|
+
const ecat = num(raw, "ECAT");
|
|
396
|
+
if (ecat !== void 0) out.emitterCategory = ecat;
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
case "155": {
|
|
400
|
+
const v = num(raw, "BVR");
|
|
401
|
+
if (v !== void 0) out.verticalRateFpm = v;
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
case "157": {
|
|
405
|
+
const v = num(raw, "GVR");
|
|
406
|
+
if (v !== void 0 && out.verticalRateFpm === void 0) out.verticalRateFpm = v;
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
332
409
|
case "010": {
|
|
333
410
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
334
411
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -570,6 +647,10 @@ function cat010(id, d, out, raw) {
|
|
|
570
647
|
trdFlags(raw, out);
|
|
571
648
|
break;
|
|
572
649
|
// I010/020 TRD
|
|
650
|
+
case "270":
|
|
651
|
+
targetSize(raw, out);
|
|
652
|
+
break;
|
|
653
|
+
// I010/270 Target Size and Orientation
|
|
573
654
|
case "010": {
|
|
574
655
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
575
656
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -637,19 +718,6 @@ function cat010(id, d, out, raw) {
|
|
|
637
718
|
}
|
|
638
719
|
}
|
|
639
720
|
var MS_TO_KT = 1 / 0.514444;
|
|
640
|
-
function flightPlanCallsign(d) {
|
|
641
|
-
let indicators = 0;
|
|
642
|
-
while (indicators < d.length) {
|
|
643
|
-
indicators++;
|
|
644
|
-
if ((d[indicators - 1] & 1) === 0) break;
|
|
645
|
-
}
|
|
646
|
-
const first = d[0] ?? 0;
|
|
647
|
-
if ((first & 64) === 0) return void 0;
|
|
648
|
-
const at = indicators + ((first & 128) !== 0 ? 2 : 0);
|
|
649
|
-
if (d.length < at + 7) return void 0;
|
|
650
|
-
const text = d.subarray(at, at + 7).toString("latin1").trim();
|
|
651
|
-
return text.length > 0 && /^[A-Z0-9 ]+$/.test(text) ? text : void 0;
|
|
652
|
-
}
|
|
653
721
|
function cat062(id, d, out, raw) {
|
|
654
722
|
switch (id) {
|
|
655
723
|
case "080":
|
|
@@ -695,6 +763,15 @@ function cat062(id, d, out, raw) {
|
|
|
695
763
|
else if (d.length >= 2) out.trackNumber = d.readUIntBE(0, 2);
|
|
696
764
|
break;
|
|
697
765
|
}
|
|
766
|
+
case "220": {
|
|
767
|
+
const roc = num(raw, "RoC");
|
|
768
|
+
if (roc !== void 0) out.verticalRateFpm = roc;
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
case "270":
|
|
772
|
+
targetSize(raw, out);
|
|
773
|
+
break;
|
|
774
|
+
// Target Size and Orientation
|
|
698
775
|
case "300": {
|
|
699
776
|
const vfi = num(raw, "VFI");
|
|
700
777
|
out.vehicleFleet = vfi ?? (d.length >= 1 ? d[0] : void 0);
|
|
@@ -708,27 +785,30 @@ function cat062(id, d, out, raw) {
|
|
|
708
785
|
break;
|
|
709
786
|
}
|
|
710
787
|
case "390": {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
788
|
+
const at = compoundSubfields(d, flightPlanSize);
|
|
789
|
+
const csn = asciiAt(d, at.get(1), 7);
|
|
790
|
+
if (csn && out.callsign === void 0) out.callsign = csn;
|
|
791
|
+
const tac = asciiAt(d, at.get(4), 4);
|
|
792
|
+
if (tac) out.aircraftType = tac;
|
|
793
|
+
const wtc = asciiAt(d, at.get(5), 1);
|
|
794
|
+
if (wtc) out.wakeTurbulence = wtc;
|
|
795
|
+
const dep = asciiAt(d, at.get(6), 4);
|
|
796
|
+
if (dep) out.departureAirport = dep;
|
|
797
|
+
const dst = asciiAt(d, at.get(7), 4);
|
|
798
|
+
if (dst) out.destinationAirport = dst;
|
|
715
799
|
break;
|
|
716
800
|
}
|
|
717
801
|
case "380": {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
out.icao24 = d.readUIntBE(at, 3).toString(16).padStart(6, "0");
|
|
726
|
-
at += 3;
|
|
727
|
-
}
|
|
728
|
-
if (fsLen < d.length && (d[0] & 64) !== 0 && d.length >= at + 6 && out.callsign === void 0) {
|
|
729
|
-
const id2 = readCallsign(d.subarray(at, at + 6));
|
|
730
|
-
if (id2) out.callsign = id2;
|
|
802
|
+
const at = compoundSubfields(d, derivedDataSize);
|
|
803
|
+
const adr = at.get(0);
|
|
804
|
+
if (adr !== void 0 && d.length >= adr + 3) out.icao24 = d.readUIntBE(adr, 3).toString(16).padStart(6, "0");
|
|
805
|
+
const id2 = at.get(1);
|
|
806
|
+
if (id2 !== void 0 && d.length >= id2 + 6 && out.callsign === void 0) {
|
|
807
|
+
const name = readCallsign(d.subarray(id2, id2 + 6));
|
|
808
|
+
if (name) out.callsign = name;
|
|
731
809
|
}
|
|
810
|
+
const sab = at.get(10);
|
|
811
|
+
if (sab !== void 0 && sab < d.length) out.onGround = (d[sab] >> 1 & 1) === 1;
|
|
732
812
|
break;
|
|
733
813
|
}
|
|
734
814
|
case "070": {
|
|
@@ -936,12 +1016,12 @@ function parseAsterixBlocks(buf, defaultEdition) {
|
|
|
936
1016
|
for (const edition of toTry) {
|
|
937
1017
|
const def = loadDef(cat, edition);
|
|
938
1018
|
if (!def) continue;
|
|
939
|
-
const { all, consumed } = decodeRecords(block, def, cat);
|
|
1019
|
+
const { all, consumed, full } = decodeRecords(block, def, cat);
|
|
940
1020
|
const first = all[0];
|
|
941
1021
|
if (!first) continue;
|
|
942
1022
|
const score = plausibilityScore(first);
|
|
943
|
-
if (!best || score > best.score) {
|
|
944
|
-
best = { edition, all, consumed, score };
|
|
1023
|
+
if (!best || full && !best.full || full === best.full && score > best.score) {
|
|
1024
|
+
best = { edition, all, consumed, score, full };
|
|
945
1025
|
}
|
|
946
1026
|
}
|
|
947
1027
|
blocks.push({
|
|
@@ -949,36 +1029,53 @@ function parseAsterixBlocks(buf, defaultEdition) {
|
|
|
949
1029
|
edition: best?.edition ?? null,
|
|
950
1030
|
length: block.length,
|
|
951
1031
|
consumed: best?.consumed ?? 0,
|
|
1032
|
+
clean: best?.full ?? false,
|
|
952
1033
|
records: best?.all ?? []
|
|
953
1034
|
});
|
|
954
1035
|
}
|
|
955
1036
|
return blocks;
|
|
956
1037
|
}
|
|
957
1038
|
function decodeRecords(block, def, cat) {
|
|
958
|
-
const
|
|
1039
|
+
const records = [];
|
|
959
1040
|
let pos = 0;
|
|
960
|
-
let
|
|
1041
|
+
let clean = false;
|
|
961
1042
|
while (pos < block.length) {
|
|
962
1043
|
const fields = {};
|
|
963
1044
|
let result;
|
|
964
1045
|
try {
|
|
965
1046
|
result = decodeBlock(block.subarray(pos), def, (id, data, itemDef) => {
|
|
966
|
-
|
|
967
|
-
const bitData = itemDef.type === "variable" ? data.subarray(0, itemDef.chunkBytes) : data;
|
|
968
|
-
const raw = bits?.length ? extractBitFields(bitData, bits) : {};
|
|
969
|
-
decodeKnownField(cat, id, data, fields, raw);
|
|
1047
|
+
decodeKnownField(cat, id, data, fields, extractItemBits(itemDef, data));
|
|
970
1048
|
});
|
|
971
1049
|
} catch {
|
|
972
1050
|
break;
|
|
973
1051
|
}
|
|
974
1052
|
if (!isPlausible(fields)) break;
|
|
975
|
-
if (
|
|
976
|
-
|
|
977
|
-
if (!result.complete || result.end <= 0) break;
|
|
1053
|
+
if (result.overrun && records.length > 0) break;
|
|
1054
|
+
records.push({ fields, end: pos + result.end });
|
|
1055
|
+
if (!result.complete || result.end <= 0 || result.overrun) break;
|
|
978
1056
|
pos += result.end;
|
|
979
|
-
|
|
1057
|
+
clean = pos >= block.length;
|
|
1058
|
+
}
|
|
1059
|
+
if (clean) {
|
|
1060
|
+
const kept = records.filter((r, i) => i === 0 || Object.keys(r.fields).length > 0).map((r) => r.fields);
|
|
1061
|
+
return { all: kept, consumed: block.length, full: true };
|
|
980
1062
|
}
|
|
981
|
-
|
|
1063
|
+
const firstEmpty = records.findIndex((r, i) => i > 0 && Object.keys(r.fields).length === 0);
|
|
1064
|
+
const usable = firstEmpty === -1 ? records : records.slice(0, firstEmpty);
|
|
1065
|
+
return { all: usable.map((r) => r.fields), consumed: usable.length > 0 ? usable[usable.length - 1].end : 0, full: false };
|
|
1066
|
+
}
|
|
1067
|
+
function extractItemBits(itemDef, data) {
|
|
1068
|
+
if (itemDef.type === "fixed") return itemDef.bits?.length ? extractBitFields(data, itemDef.bits) : {};
|
|
1069
|
+
if (itemDef.type !== "variable") return {};
|
|
1070
|
+
const chunks = itemDef.chunks?.length ? itemDef.chunks : itemDef.bits ? [itemDef.bits] : [];
|
|
1071
|
+
const out = {};
|
|
1072
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
1073
|
+
const start = i * itemDef.chunkBytes;
|
|
1074
|
+
if (start + itemDef.chunkBytes > data.length) break;
|
|
1075
|
+
const part = extractBitFields(data.subarray(start, start + itemDef.chunkBytes), chunks[i]);
|
|
1076
|
+
for (const [name, value] of Object.entries(part)) if (!(name in out)) out[name] = value;
|
|
1077
|
+
}
|
|
1078
|
+
return out;
|
|
982
1079
|
}
|
|
983
1080
|
function isPlausible(f) {
|
|
984
1081
|
if (f.lat !== void 0 && (f.lat < -90 || f.lat > 90)) return false;
|
|
@@ -1333,6 +1430,7 @@ export {
|
|
|
1333
1430
|
decodeMlatFrame,
|
|
1334
1431
|
parseAftn,
|
|
1335
1432
|
parseAsterix,
|
|
1433
|
+
parseAsterixBlocks,
|
|
1336
1434
|
resolveAsterixAltitudeFt,
|
|
1337
1435
|
resolveAsterixPosition,
|
|
1338
1436
|
splitAftnStream
|
|
@@ -4,16 +4,21 @@ export declare function parseFspec(buf: Buffer, start?: number): {
|
|
|
4
4
|
bits: boolean[];
|
|
5
5
|
end: number;
|
|
6
6
|
};
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Advance offset past one DataItem, returning new offset. The result is NOT clamped to the buffer: an offset past
|
|
9
|
+
* `buf.length` means the item needs more octets than there are (an overrun), which `decodeBlock` reports.
|
|
10
|
+
*/
|
|
8
11
|
export declare function skipItem(buf: Buffer, off: number, def: ItemDef): number;
|
|
9
12
|
/**
|
|
10
13
|
* Decode ONE record at the start of `block` (a data block can carry many records back to back, each with its own
|
|
11
14
|
* FSPEC). Calls `onField(id, bytes, itemDef)` for each present DataItem. Returns where the record ended, so the caller
|
|
12
15
|
* can go on with the next one, and whether that position can be trusted: `complete` is false when an item the
|
|
13
|
-
* definition does not know stopped the decode (the length of what follows is then unknown)
|
|
16
|
+
* definition does not know stopped the decode (the length of what follows is then unknown); `overrun` is true when an
|
|
17
|
+
* item needed more octets than the block has (the record is cut short or an item was sized wrongly).
|
|
14
18
|
*/
|
|
15
19
|
export declare function decodeBlock(block: Buffer, def: AsterixDef, onField: (id: string, data: Buffer, itemDef: ItemDef) => void): {
|
|
16
20
|
end: number;
|
|
17
21
|
complete: boolean;
|
|
22
|
+
overrun: boolean;
|
|
18
23
|
};
|
|
19
24
|
//# sourceMappingURL=decoder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI3D,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAUnF;AAID
|
|
1
|
+
{"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI3D,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAUnF;AAID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAiDvE;AAID;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAC5D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA2BtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor-fields.test.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/descriptor-fields.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAwI7C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,GAAE,SAAc,GAAG,IAAI,CAWrH"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { parseAsterix } from './parser.js';
|
|
1
|
+
export { parseAsterix, parseAsterixBlocks } from './parser.js';
|
|
2
|
+
export type { AsterixBlockInfo } from './parser.js';
|
|
2
3
|
export { resolveAsterixPosition, resolveAsterixAltitudeFt } from './resolvers.js';
|
|
3
4
|
export type { RadarSite } from './resolvers.js';
|
|
4
5
|
export type { AsterixRecord, AsterixFields } from './types.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -19,8 +19,10 @@ export interface AsterixBlockInfo {
|
|
|
19
19
|
edition: string | null;
|
|
20
20
|
/** Octets of the block after its 3-octet header. */
|
|
21
21
|
length: number;
|
|
22
|
-
/** Octets taken up by the decoded records.
|
|
22
|
+
/** Octets taken up by the decoded records. */
|
|
23
23
|
consumed: number;
|
|
24
|
+
/** The records tile the block exactly: no octets left over, none missing, no item that ran past the end. False points at an item sized wrongly or a tail that was not understood. */
|
|
25
|
+
clean: boolean;
|
|
24
26
|
records: AsterixFields[];
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAsB/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,aAAa,EAAE,CAOjB;AAED,iJAAiJ;AACjJ,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAsB/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,aAAa,EAAE,CAOjB;AAED,iJAAiJ;AACjJ,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,qLAAqL;IACrL,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,gBAAgB,EAAE,CA2CpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repetitive.test.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/repetitive.test.ts"],"names":[],"mappings":""}
|
|
@@ -41,6 +41,25 @@ export interface AsterixFields {
|
|
|
41
41
|
vehicleFleet?: number;
|
|
42
42
|
/** Sensor-assigned local track number */
|
|
43
43
|
trackNumber?: number;
|
|
44
|
+
/** Ground bit: true = the target reports being on the ground, false = not. Undefined = not reported (CAT010/020/021 descriptor, CAT062 I062/380 SAB). */
|
|
45
|
+
onGround?: boolean;
|
|
46
|
+
/** ICAO aircraft type designator, e.g. "A320" (CAT062 I062/390 TAC) */
|
|
47
|
+
aircraftType?: string;
|
|
48
|
+
/** Wake turbulence category: L, M, H or J (CAT062 I062/390 WTC) */
|
|
49
|
+
wakeTurbulence?: string;
|
|
50
|
+
/** Departure and destination aerodrome, ICAO (CAT062 I062/390 DEP, DST) */
|
|
51
|
+
departureAirport?: string;
|
|
52
|
+
destinationAirport?: string;
|
|
53
|
+
/** Rate of climb (+) or descent (-), ft/min (CAT062 I062/220, CAT021 I021/155 baro, else I021/157 geometric) */
|
|
54
|
+
verticalRateFpm?: number;
|
|
55
|
+
/** Size and heading of the target on the surface (CAT062 I062/270, CAT010 I010/270) */
|
|
56
|
+
targetSize?: {
|
|
57
|
+
lengthM?: number;
|
|
58
|
+
widthM?: number;
|
|
59
|
+
orientationDeg?: number;
|
|
60
|
+
};
|
|
61
|
+
/** Emitter category of an ADS-B target (CAT021 I021/020 ECAT) */
|
|
62
|
+
emitterCategory?: number;
|
|
44
63
|
/** TST bit — test target */
|
|
45
64
|
testTarget?: boolean;
|
|
46
65
|
/** RAB bit — report from a fixed field-monitor transponder (MLAT RPU etc.) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,iBAAiB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,gBAAgB,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1C,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACnG,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,iBAAiB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,gBAAgB,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1C,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACnG,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yJAAyJ;IACzJ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gHAAgH;IAChH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uFAAuF;IACvF,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iCAAiC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;CACvB"}
|
|
@@ -13,10 +13,12 @@ export type FixedDef = {
|
|
|
13
13
|
bytes: number;
|
|
14
14
|
bits?: BitFieldDef[];
|
|
15
15
|
};
|
|
16
|
+
/** `bits` = the first octet's fields; `chunks` = the fields of every octet in order (the first extension re-numbers from bit 1). */
|
|
16
17
|
export type VariableDef = {
|
|
17
18
|
type: 'variable';
|
|
18
19
|
chunkBytes: number;
|
|
19
20
|
bits?: BitFieldDef[];
|
|
21
|
+
chunks?: BitFieldDef[][];
|
|
20
22
|
};
|
|
21
23
|
export type RepDef = {
|
|
22
24
|
type: 'repetitive';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-loader.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/xml-loader.ts"],"names":[],"mappings":"AAgBA;kEACkE;AAClE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IACxE,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,GAAQ;IAAE,IAAI,EAAE,OAAO,CAAC;IAAM,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC;AACxF,MAAM,MAAM,WAAW,GAAK;IAAE,IAAI,EAAE,UAAU,CAAC;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"xml-loader.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/xml-loader.ts"],"names":[],"mappings":"AAgBA;kEACkE;AAClE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IACxE,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,GAAQ;IAAE,IAAI,EAAE,OAAO,CAAC;IAAM,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC;AACxF,oIAAoI;AACpI,MAAM,MAAM,WAAW,GAAK;IAAE,IAAI,EAAE,UAAU,CAAC;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,EAAE,EAAE,CAAA;CAAE,CAAC;AACvH,MAAM,MAAM,MAAM,GAAU;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AACxF,MAAM,MAAM,WAAW,GAAK;IAAE,IAAI,EAAE,UAAU,CAAC;IAAG,cAAc,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,WAAW,GAAK;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AACjD,MAAM,MAAM,UAAU,GAAM,QAAQ,GAAG,WAAW,GAAG,MAAM,GAAG,WAAW,CAAC;AAC1E,MAAM,MAAM,OAAO,GAAS,QAAQ,GAAG,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC;AAExF,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,QAAQ,EAAE,CAAC;IAChB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B;AAgCD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAgBlE"}
|