gnss-js 1.13.0 → 1.14.0

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/sbf.cjs ADDED
@@ -0,0 +1,747 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/sbf/index.ts
21
+ var sbf_exports = {};
22
+ __export(sbf_exports, {
23
+ parseSbfMeas: () => parseSbfMeas
24
+ });
25
+ module.exports = __toCommonJS(sbf_exports);
26
+ var CLIGHT = 299792458;
27
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
28
+ var MS_PER_WEEK = 7 * 864e5;
29
+ var CRC_TABLE = (() => {
30
+ const t = new Uint16Array(256);
31
+ for (let n = 0; n < 256; n++) {
32
+ let c = n << 8;
33
+ for (let k = 0; k < 8; k++)
34
+ c = c & 32768 ? (c << 1 ^ 4129) & 65535 : c << 1 & 65535;
35
+ t[n] = c;
36
+ }
37
+ return t;
38
+ })();
39
+ function crc16(data, start, end) {
40
+ let crc = 0;
41
+ for (let i = start; i < end; i++)
42
+ crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
43
+ return crc;
44
+ }
45
+ var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
46
+ var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
47
+ var M3_INTERVALS = [
48
+ 1,
49
+ 500,
50
+ 1e3,
51
+ 2e3,
52
+ 5e3,
53
+ 1e4,
54
+ 15e3,
55
+ 3e4,
56
+ 6e4,
57
+ 12e4,
58
+ 1,
59
+ 1,
60
+ 1,
61
+ 1,
62
+ 1,
63
+ 1
64
+ ];
65
+ var M3_LOCK_TIME = [
66
+ 0,
67
+ 6e4,
68
+ 3e4,
69
+ 15e3,
70
+ 1e4,
71
+ 5e3,
72
+ 2e3,
73
+ 1e3,
74
+ 500,
75
+ 200,
76
+ 100,
77
+ 50,
78
+ 40,
79
+ 20,
80
+ 10,
81
+ 0
82
+ ];
83
+ var M3_SIG_DEFAULT = [
84
+ ["1C", "2L", "5Q", "1W", "2W", "1L"],
85
+ // GPS
86
+ ["1C", "2C", "1P", "2P", "3Q"],
87
+ // GLONASS
88
+ ["1C", "5Q", "7Q", "6C", "8Q"],
89
+ // Galileo
90
+ ["2I", "7I", "6I", "1P", "5P", "7D"],
91
+ // BeiDou
92
+ ["1C", "5I"],
93
+ // SBAS
94
+ ["1C", "2L", "5Q", "6L", "1L", "1Z", "5P", "1E"],
95
+ // QZSS
96
+ ["5A", "1E", "9A"]
97
+ // NavIC
98
+ ];
99
+ var MEAS2_SIG = [
100
+ ["G", "1C"],
101
+ ["G", "1W"],
102
+ ["G", "2W"],
103
+ ["G", "2L"],
104
+ ["G", "5Q"],
105
+ ["G", "1L"],
106
+ ["J", "1C"],
107
+ ["J", "2L"],
108
+ ["R", "1C"],
109
+ ["R", "1P"],
110
+ ["R", "2P"],
111
+ ["R", "2C"],
112
+ ["R", "3Q"],
113
+ ["C", "1P"],
114
+ ["C", "5P"],
115
+ ["I", "5A"],
116
+ null,
117
+ ["E", "1C"],
118
+ null,
119
+ ["E", "6C"],
120
+ ["E", "5Q"],
121
+ ["E", "7Q"],
122
+ ["E", "8Q"],
123
+ null,
124
+ // L-band
125
+ ["S", "1C"],
126
+ ["S", "5I"],
127
+ ["J", "5Q"],
128
+ ["J", "6L"],
129
+ ["C", "2I"],
130
+ ["C", "7I"],
131
+ ["C", "6I"],
132
+ null,
133
+ ["J", "1L"],
134
+ ["J", "1Z"],
135
+ ["C", "7D"],
136
+ null,
137
+ ["I", "9A"],
138
+ null,
139
+ // NavIC L1 (no obs code assigned)
140
+ ["J", "1E"],
141
+ ["J", "5P"]
142
+ ];
143
+ var two = (n) => String(n).padStart(2, "0");
144
+ function m3Prn(navsys, svid) {
145
+ switch (navsys) {
146
+ case 0:
147
+ return svid < 32 ? `G${two(svid + 1)}` : null;
148
+ case 1:
149
+ return svid < 27 ? `R${two(svid + 1)}` : null;
150
+ case 2:
151
+ return svid < 36 ? `E${two(svid + 1)}` : null;
152
+ case 3:
153
+ return svid < 50 ? `C${two(svid + 1)}` : null;
154
+ case 4:
155
+ return svid <= 38 ? `S${two(svid + 20)}` : null;
156
+ case 5:
157
+ return svid < 10 ? `J${two(svid + 1)}` : null;
158
+ case 6:
159
+ return svid < 14 ? `I${two(svid + 1)}` : null;
160
+ default:
161
+ return null;
162
+ }
163
+ }
164
+ function svidToPrn(svid) {
165
+ if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
166
+ if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
167
+ if (svid <= 62) return null;
168
+ if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
169
+ if (svid <= 70) return null;
170
+ if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
171
+ if (svid <= 119) return null;
172
+ if (svid <= 140) return `S${two(svid - 100)}`;
173
+ if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
174
+ if (svid <= 190) return `J${two(svid - 180)}`;
175
+ if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
176
+ if (svid <= 215) return `S${two(svid - 157)}`;
177
+ if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
178
+ if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
179
+ return null;
180
+ }
181
+ function carrierFreq(sys, code, fcn) {
182
+ const band = code.charCodeAt(0) - 48;
183
+ switch (sys) {
184
+ case "G":
185
+ case "J":
186
+ if (band === 1) return 157542e4;
187
+ if (band === 2) return 12276e5;
188
+ if (band === 5) return 117645e4;
189
+ if (band === 6) return 127875e4;
190
+ return 0;
191
+ case "R":
192
+ if (band === 1) return 1602e6 + fcn * 562500;
193
+ if (band === 2) return 1246e6 + fcn * 437500;
194
+ if (band === 3) return 1202025e3;
195
+ return 0;
196
+ case "E":
197
+ if (band === 1) return 157542e4;
198
+ if (band === 5) return 117645e4;
199
+ if (band === 6) return 127875e4;
200
+ if (band === 7) return 120714e4;
201
+ if (band === 8) return 1191795e3;
202
+ return 0;
203
+ case "C":
204
+ if (band === 1) return 157542e4;
205
+ if (band === 2) return 1561098e3;
206
+ if (band === 5) return 117645e4;
207
+ if (band === 6) return 126852e4;
208
+ if (band === 7) return 120714e4;
209
+ if (band === 8) return 1191795e3;
210
+ return 0;
211
+ case "S":
212
+ if (band === 1) return 157542e4;
213
+ if (band === 5) return 117645e4;
214
+ return 0;
215
+ case "I":
216
+ if (band === 1) return 157542e4;
217
+ if (band === 5) return 117645e4;
218
+ if (band === 9) return 2492028e3;
219
+ return 0;
220
+ default:
221
+ return 0;
222
+ }
223
+ }
224
+ var ZERO_REF_SLOT = {
225
+ sigIdx: 0,
226
+ pr: 0,
227
+ cp: 0,
228
+ cn0: 0,
229
+ lockTimeMs: null
230
+ };
231
+ function freshRefEpoch(tow) {
232
+ return {
233
+ tow,
234
+ headers: new Array(7).fill(null),
235
+ sats: Array.from({ length: 7 }, () => new Array(64))
236
+ };
237
+ }
238
+ function parseSbfMeas(data) {
239
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
240
+ const epochs = [];
241
+ const messageCounts = {};
242
+ const obsCodes = {};
243
+ let badCrc = 0;
244
+ let ref = freshRefEpoch(-1);
245
+ let curTime = NaN;
246
+ let curMeas = [];
247
+ let curSats = [];
248
+ const flush = () => {
249
+ if (curMeas.length > 0) {
250
+ const meas = curMeas.map((m) => {
251
+ const codes = obsCodes[m.sys] ??= [];
252
+ if (!codes.includes(m.code)) codes.push(m.code);
253
+ return {
254
+ prn: m.prn,
255
+ code: m.code,
256
+ pr: m.pr !== 0 ? m.pr : null,
257
+ cp: m.cp !== 0 ? m.cp : null,
258
+ doppler: m.doppler,
259
+ cn0: m.cn0,
260
+ lockTimeMs: m.lockTimeMs
261
+ };
262
+ });
263
+ epochs.push({ timeMs: curTime, meas });
264
+ }
265
+ curMeas = [];
266
+ curSats = [];
267
+ };
268
+ const ensureEpoch = (timeMs) => {
269
+ if (timeMs !== curTime) {
270
+ flush();
271
+ curTime = timeMs;
272
+ }
273
+ };
274
+ const decodeMeas3Ranges = (i2, tow) => {
275
+ const o = i2 + 8;
276
+ const constellations = view.getUint16(o + 8, true) & 127;
277
+ const misc = data[o + 10];
278
+ const version = data[o + 11];
279
+ if (version > 31) return;
280
+ if ((misc & 7) !== 0) return;
281
+ const prrAvailable = (misc & 8) !== 0;
282
+ const interval = M3_INTERVALS[misc >> 4];
283
+ const isRef = tow % interval === 0;
284
+ const dtow = tow % interval;
285
+ if (isRef) {
286
+ ref = freshRefEpoch(tow);
287
+ } else if (ref.tow !== Math.floor(tow / interval) * interval) {
288
+ curMeas = [];
289
+ curSats = [];
290
+ return;
291
+ }
292
+ let idx = o + 12;
293
+ for (let navsys = 0; navsys < 7; navsys++) {
294
+ if ((constellations & 1 << navsys) === 0) continue;
295
+ const sys = M3_SYS[navsys];
296
+ const useRefHeader = data[idx] === 0;
297
+ const hdr = useRefHeader ? ref.headers[navsys] ?? new Uint8Array(0) : data.subarray(idx, idx + 32);
298
+ const BF1 = hdr[0] ?? 0;
299
+ let nB = BF1 & 7;
300
+ if (nB === 7) nB = 8;
301
+ const sigIdxMasterShort = BF1 >> 3 & 15;
302
+ const sigExclPresent = BF1 >> 7 !== 0;
303
+ let h = 1;
304
+ const maskBytes = hdr.subarray(h, h + nB);
305
+ let nSats = 0;
306
+ for (const b of maskBytes)
307
+ for (let k = 0; k < 8; k++) nSats += b >> k & 1;
308
+ h += nB;
309
+ let gloFncs = new Uint8Array(0);
310
+ let bdsLongRange = 0;
311
+ if (navsys === 1) {
312
+ gloFncs = hdr.subarray(h, h + (nSats + 1 >> 1));
313
+ h += nSats + 1 >> 1;
314
+ } else if (navsys === 3) {
315
+ bdsLongRange = (hdr[h] ?? 0) | (hdr[h + 1] ?? 0) << 8;
316
+ h += 2;
317
+ }
318
+ const sigExcluded = sigExclPresent ? hdr[h++] ?? 0 : 0;
319
+ if (isRef) ref.headers[navsys] = data.slice(idx, idx + h);
320
+ idx += useRefHeader ? 1 : h;
321
+ const sigTable = [];
322
+ for (let s = 0; s < 16; s++)
323
+ if ((sigExcluded & 1 << s) === 0)
324
+ sigTable.push(M3_SIG_DEFAULT[navsys][s] ?? null);
325
+ while (sigTable.length < 16) sigTable.push(null);
326
+ let satCnt = 0;
327
+ for (let svid = 0; svid < 64 && satCnt < nSats; svid++) {
328
+ if (((maskBytes[svid >> 3] ?? 0) >> (svid & 7) & 1) === 0) continue;
329
+ const glofnc = navsys === 1 ? ((gloFncs[satCnt >> 1] ?? 0) >> 4 * (satCnt % 2) & 15) - 8 : 0;
330
+ const prn = m3Prn(navsys, svid);
331
+ const prbase = navsys === 3 && (bdsLongRange & 1 << satCnt) !== 0 ? 34e6 : M3_PR_BASE[navsys];
332
+ const refSat = ref.sats[navsys][svid];
333
+ const refSlot = (k) => refSat?.slots[k] ?? ZERO_REF_SLOT;
334
+ const entry = { navsys, svid, prn, slots: [] };
335
+ const bt = data[idx];
336
+ let masterSigIdx;
337
+ let slaveMask;
338
+ let prRate = 0;
339
+ let mPr = 0;
340
+ let mCp = 0;
341
+ let mCn0 = 0;
342
+ let mLock = null;
343
+ let masterCode;
344
+ let mFreq = 0;
345
+ if ((bt & 1) === 1) {
346
+ const BF1m = view.getUint32(idx, true);
347
+ const prLsb = view.getUint32(idx + 4, true);
348
+ const cmc = BF1m >>> 1 & 262143;
349
+ const prMsb = BF1m >>> 19 & 1;
350
+ const lti3 = BF1m >>> 20 & 7;
351
+ const cn0 = BF1m >>> 23 & 31;
352
+ const signalList = BF1m >>> 28 & 15;
353
+ masterSigIdx = sigIdxMasterShort;
354
+ slaveMask = signalList << masterSigIdx + 1;
355
+ masterCode = sigTable[masterSigIdx] ?? null;
356
+ if (masterCode) {
357
+ mFreq = carrierFreq(sys, masterCode, glofnc);
358
+ mPr = prbase + (prLsb + 4294967296 * prMsb) * 1e-3;
359
+ mCn0 = cn0 + 24;
360
+ if (cmc !== 0) mCp = mPr / (CLIGHT / mFreq) - 131.072 + cmc * 1e-3;
361
+ mLock = M3_LOCK_TIME[lti3];
362
+ }
363
+ prRate = prrAvailable ? view.getInt16(idx + 8, true) : 0;
364
+ idx += prrAvailable ? 10 : 8;
365
+ } else if ((bt & 3) === 0) {
366
+ const BF1m = view.getUint32(idx, true);
367
+ const prLsb = view.getUint32(idx + 4, true);
368
+ const BF2 = view.getUint16(idx + 8, true);
369
+ const BF3 = data[idx + 10];
370
+ const prMsb = BF1m >>> 2 & 15;
371
+ const cmc = BF1m >>> 6 & 4194303;
372
+ const lti4 = BF1m >>> 28 & 15;
373
+ const cn0 = BF2 & 63;
374
+ let signalMask = BF2 >>> 6 & 511;
375
+ const cont = BF2 >>> 15 & 1;
376
+ if (cont !== 0) signalMask |= (BF3 & 127) << 9;
377
+ masterSigIdx = 0;
378
+ while (masterSigIdx < 32 && (signalMask >> masterSigIdx & 1) === 0)
379
+ masterSigIdx++;
380
+ slaveMask = signalMask !== 0 ? signalMask ^ 1 << masterSigIdx : 0;
381
+ masterCode = sigTable[masterSigIdx] ?? null;
382
+ if (masterCode) {
383
+ mFreq = carrierFreq(sys, masterCode, glofnc);
384
+ const isGpsPCode = navsys === 0 && (masterCode === "1W" || masterCode === "2W");
385
+ mPr = (prLsb + 4294967296 * prMsb) * 1e-3;
386
+ mCn0 = isGpsPCode ? cn0 : cn0 + 10;
387
+ if (cmc !== 0)
388
+ mCp = mPr / (CLIGHT / mFreq) - 2097.152 + cmc * 1e-3;
389
+ mLock = M3_LOCK_TIME[lti4];
390
+ }
391
+ prRate = prrAvailable ? view.getInt16(idx + 10, true) : 0;
392
+ idx += (prrAvailable ? 12 : 10) + cont;
393
+ } else if ((bt & 12) === 12) {
394
+ const BF1m = data[idx];
395
+ const BF2 = view.getUint32(idx + 1, true);
396
+ const prDelta = BF1m >> 4 << 13 | BF2 & 8191;
397
+ const cn0Delta = BF2 >>> 13 & 7;
398
+ const cmc = BF2 >>> 16;
399
+ masterSigIdx = refSlot(0).sigIdx;
400
+ slaveMask = refSat?.slaveMask ?? 0;
401
+ masterCode = sigTable[masterSigIdx] ?? null;
402
+ if (masterCode) {
403
+ const r = refSlot(0);
404
+ mFreq = carrierFreq(sys, masterCode, glofnc);
405
+ mPr = r.pr + Math.trunc((refSat?.prRate ?? 0) * 64 * dtow / 1e3) * 1e-3 + prDelta * 1e-3 - 65.536;
406
+ mCn0 = r.cn0 - 4 + cn0Delta;
407
+ if (cmc !== 0)
408
+ mCp = (mPr - r.pr) / (CLIGHT / mFreq) + r.cp - 32.768 + cmc * 1e-3;
409
+ mLock = r.lockTimeMs;
410
+ }
411
+ idx += 5;
412
+ } else {
413
+ const BF1m = view.getUint32(idx, true);
414
+ const prDelta = BF1m >>> 4 & 16383;
415
+ const cmc = BF1m >>> 18 & 16383;
416
+ const cn0Delta = BF1m >>> 2 & 3;
417
+ masterSigIdx = refSlot(0).sigIdx;
418
+ slaveMask = refSat?.slaveMask ?? 0;
419
+ masterCode = sigTable[masterSigIdx] ?? null;
420
+ if (masterCode) {
421
+ const r = refSlot(0);
422
+ mFreq = carrierFreq(sys, masterCode, glofnc);
423
+ mPr = r.pr + Math.trunc((refSat?.prRate ?? 0) * 64 * dtow / 1e3) * 1e-3 + prDelta * 1e-3 - 8.192;
424
+ mCn0 = r.cn0 - 1 + cn0Delta;
425
+ if (cmc !== 0)
426
+ mCp = (mPr - r.pr) / (CLIGHT / mFreq) + r.cp - 8.192 + cmc * 1e-3;
427
+ mLock = r.lockTimeMs;
428
+ }
429
+ idx += 4;
430
+ }
431
+ let masterMeas = null;
432
+ if (masterCode && prn) {
433
+ masterMeas = {
434
+ prn,
435
+ sys,
436
+ code: masterCode,
437
+ freq: mFreq,
438
+ pr: mPr,
439
+ cp: mCp,
440
+ cn0: mCn0,
441
+ doppler: null,
442
+ lockTimeMs: mLock
443
+ };
444
+ curMeas.push(masterMeas);
445
+ }
446
+ entry.slots.push(masterMeas);
447
+ let newRefSat = null;
448
+ if (isRef && prn) {
449
+ newRefSat = {
450
+ slaveMask,
451
+ prRate,
452
+ slots: [
453
+ {
454
+ sigIdx: masterSigIdx,
455
+ pr: mPr,
456
+ cp: mCp,
457
+ cn0: mCn0,
458
+ lockTimeMs: mLock
459
+ }
460
+ ]
461
+ };
462
+ ref.sats[navsys][svid] = newRefSat;
463
+ }
464
+ let slaveCnt = 0;
465
+ let mask = slaveMask;
466
+ for (let s = 1; s < 16 && mask !== 0; s++) {
467
+ if ((mask & 1 << s) === 0) continue;
468
+ const bt2 = data[idx];
469
+ const code = sigTable[s] ?? null;
470
+ const freq = code ? carrierFreq(sys, code, glofnc) : 0;
471
+ let sPr = 0;
472
+ let sCp = 0;
473
+ let sCn0 = 0;
474
+ let sLock = null;
475
+ if ((bt2 & 1) === 1) {
476
+ const BF1s = view.getUint32(idx, true);
477
+ const BF2s = data[idx + 4];
478
+ const cmcRes = BF1s >>> 1 & 65535;
479
+ const prRel = BF1s >>> 17;
480
+ const lti3 = BF2s & 7;
481
+ const cn0 = BF2s >> 3;
482
+ if (code) {
483
+ sPr = mFreq > freq ? mPr + prRel * 1e-3 - 10 : mPr - prRel * 1e-3 + 10;
484
+ if (cmcRes !== 0)
485
+ sCp = sPr / (CLIGHT / freq) + (mCp - mPr / (CLIGHT / mFreq)) * (mFreq / freq) - 32.768 + cmcRes * 1e-3;
486
+ sCn0 = navsys === 0 && (code === "1W" || code === "2W") ? mCn0 - 3 - cn0 : cn0 + 24;
487
+ sLock = M3_LOCK_TIME[lti3];
488
+ }
489
+ idx += 5;
490
+ } else if ((bt2 & 3) === 0) {
491
+ const BF1s = view.getUint32(idx, true);
492
+ const prLsbRel = view.getUint16(idx + 4, true);
493
+ const BF3s = data[idx + 6];
494
+ const cmc = BF1s >>> 2 & 4194303;
495
+ const lti4 = BF1s >>> 24 & 15;
496
+ const prMsbRel = BF1s >>> 28 & 7;
497
+ const cn0 = BF3s & 63;
498
+ if (code) {
499
+ sPr = mPr + (prMsbRel * 65536 + prLsbRel) * 1e-3 - 262.144;
500
+ if (cmc !== 0)
501
+ sCp = sPr / (CLIGHT / freq) - 2097.152 + cmc * 1e-3;
502
+ sCn0 = navsys === 0 && (code === "1W" || code === "2W") ? cn0 : cn0 + 10;
503
+ sLock = M3_LOCK_TIME[lti4];
504
+ }
505
+ idx += 7;
506
+ } else {
507
+ const BF1s = view.getUint16(idx, true);
508
+ const dC = data[idx + 2];
509
+ const dPr = BF1s >>> 2 & 4095;
510
+ const cn0Delta = BF1s >>> 14;
511
+ if (code) {
512
+ const rS = refSlot(slaveCnt + 1);
513
+ const rM = refSlot(0);
514
+ sCp = rS.cp + (mCp - rM.cp) * (freq / mFreq) - 0.128 + dC * 1e-3;
515
+ sPr = rS.pr + (sCp - rS.cp) * (CLIGHT / freq) - 2.048 + dPr * 1e-3;
516
+ sCn0 = rS.cn0 - 2 + cn0Delta;
517
+ sLock = rS.lockTimeMs;
518
+ }
519
+ idx += 3;
520
+ }
521
+ let slaveMeas = null;
522
+ if (code && prn) {
523
+ slaveMeas = {
524
+ prn,
525
+ sys,
526
+ code,
527
+ freq,
528
+ pr: sPr,
529
+ cp: sCp,
530
+ cn0: sCn0,
531
+ doppler: null,
532
+ lockTimeMs: sLock
533
+ };
534
+ curMeas.push(slaveMeas);
535
+ }
536
+ entry.slots.push(slaveMeas);
537
+ if (newRefSat)
538
+ newRefSat.slots[slaveCnt + 1] = {
539
+ sigIdx: s,
540
+ pr: sPr,
541
+ cp: sCp,
542
+ cn0: sCn0,
543
+ lockTimeMs: sLock
544
+ };
545
+ slaveCnt++;
546
+ mask &= ~(1 << s);
547
+ }
548
+ curSats.push(entry);
549
+ satCnt++;
550
+ }
551
+ }
552
+ };
553
+ const decodeMeas3CN0 = (i2, len) => {
554
+ const flags = view.getUint16(i2 + 14, true);
555
+ if ((flags & 7) !== 0) return;
556
+ const maxNibbles = (len - 16) * 2;
557
+ let off = 0;
558
+ for (const e of curSats) {
559
+ if (off >= maxNibbles) break;
560
+ if (!e.prn) continue;
561
+ for (let k = 0; k < e.slots.length; k++) {
562
+ const slot = e.slots[k];
563
+ if (k > 0 && !slot) break;
564
+ const nib = (data[i2 + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
565
+ if (slot && slot.cn0 !== null) slot.cn0 += nib * 0.0625 - 0.5;
566
+ off++;
567
+ }
568
+ }
569
+ };
570
+ const readPrRate = (base, off) => {
571
+ const byteAt = (k) => data[base + off + k] ?? 0;
572
+ const v = (byteAt(0) | byteAt(1) << 8 | byteAt(2) << 16 | byteAt(3) << 24) >>> 0;
573
+ let value;
574
+ let size;
575
+ if ((v & 2) === 0) {
576
+ value = (v & 255) >>> 2;
577
+ size = 1;
578
+ } else if ((v & 6) === 2) {
579
+ value = (v & 65535) >>> 3;
580
+ size = 2;
581
+ } else if ((v & 14) === 6) {
582
+ value = (v & 16777215) >>> 4;
583
+ size = 3;
584
+ } else {
585
+ value = v >>> 4;
586
+ size = 4;
587
+ }
588
+ if ((v & 1) === 1) value = -value;
589
+ return { value, size };
590
+ };
591
+ const decodeMeas3Doppler = (i2, len) => {
592
+ const flags = view.getUint16(i2 + 14, true);
593
+ if ((flags & 7) !== 0) return;
594
+ let off = 0;
595
+ for (const e of curSats) {
596
+ if (off + 16 >= len) break;
597
+ if (!e.prn) continue;
598
+ const master = readPrRate(i2 + 16, off);
599
+ off += master.size;
600
+ if (master.value === -268435455) continue;
601
+ const refPrRate = ref.sats[e.navsys][e.svid]?.prRate ?? 0;
602
+ const m = e.slots[0];
603
+ const mD = m ? -(master.value + refPrRate * 64) * 1e-3 / (CLIGHT / m.freq) : 0;
604
+ if (m) m.doppler = mD;
605
+ for (let k = 1; k < e.slots.length; k++) {
606
+ const slot = e.slots[k];
607
+ if (!slot) break;
608
+ const slave = readPrRate(i2 + 16, off);
609
+ off += slave.size;
610
+ if (m)
611
+ slot.doppler = (mD * (CLIGHT / m.freq) * 1e3 - slave.value) * 1e-3 / (CLIGHT / slot.freq);
612
+ }
613
+ }
614
+ };
615
+ const decodeMeasEpoch = (i2, len) => {
616
+ const n1 = data[i2 + 14];
617
+ const len1 = data[i2 + 15];
618
+ const len2 = data[i2 + 16];
619
+ if ((data[i2 + 17] & 128) !== 0) return;
620
+ const end = i2 + len;
621
+ let p = i2 + 20;
622
+ for (let b1 = 0; b1 < n1 && p + 20 <= end; b1++) {
623
+ const ant = data[p + 1] >> 5;
624
+ let sig = data[p + 1] & 31;
625
+ const svid = data[p + 2];
626
+ const misc = data[p + 3];
627
+ const info = data[p + 18];
628
+ const n2 = data[p + 19];
629
+ let fcn = 0;
630
+ if (sig === 31) sig = (info >> 3) + 32;
631
+ else if (sig >= 8 && sig <= 11) fcn = (info >> 3) - 8;
632
+ const prn = svidToPrn(svid);
633
+ const sigDef = MEAS2_SIG[sig] ?? null;
634
+ if (ant !== 0 || !prn || !sigDef || sigDef[0] !== prn[0]) {
635
+ p += len1 + len2 * n2;
636
+ continue;
637
+ }
638
+ const [sys, code] = sigDef;
639
+ const freq1 = carrierFreq(sys, code, fcn);
640
+ const codeLsb = view.getUint32(p + 4, true);
641
+ const dopplerRaw = view.getInt32(p + 8, true);
642
+ const carrierLsb = view.getUint16(p + 12, true);
643
+ const carrierMsb = view.getInt8(p + 14);
644
+ const cn0Raw = data[p + 15];
645
+ const lock = view.getUint16(p + 16, true);
646
+ let p1 = 0;
647
+ if ((misc & 15) !== 0 || codeLsb !== 0)
648
+ p1 = (misc & 15) * 4294967296e-3 + codeLsb * 1e-3;
649
+ const d1 = dopplerRaw !== -2147483648 ? dopplerRaw * 1e-4 : null;
650
+ let l1 = 0;
651
+ if (p1 !== 0 && freq1 > 0 && lock !== 65535 && (carrierMsb !== -128 || carrierLsb !== 0))
652
+ l1 = p1 * freq1 / CLIGHT + carrierMsb * 65.536 + carrierLsb * 1e-3;
653
+ const cn0 = cn0Raw !== 255 ? cn0Raw * 0.25 + (sig === 1 || sig === 2 ? 0 : 10) : null;
654
+ curMeas.push({
655
+ prn,
656
+ sys,
657
+ code,
658
+ freq: freq1,
659
+ pr: p1,
660
+ cp: l1,
661
+ cn0,
662
+ doppler: d1,
663
+ lockTimeMs: lock !== 65535 ? lock * 1e3 : null
664
+ });
665
+ p += len1;
666
+ for (let b2 = 0; b2 < n2 && p + 12 <= end; b2++, p += len2) {
667
+ let sig2 = data[p] & 31;
668
+ const ant2 = data[p] >> 5;
669
+ const lock2 = data[p + 1];
670
+ const cn0Raw2 = data[p + 2];
671
+ const offsetsMsb = data[p + 3];
672
+ const carrierMsb2 = view.getInt8(p + 4);
673
+ const info2 = data[p + 5];
674
+ if (sig2 === 31) sig2 = (info2 >> 3) + 32;
675
+ const sigDef2 = MEAS2_SIG[sig2] ?? null;
676
+ if (ant2 !== 0 || !sigDef2 || sigDef2[0] !== prn[0]) continue;
677
+ const code2 = sigDef2[1];
678
+ const freq2 = carrierFreq(sys, code2, fcn);
679
+ const codeOffMsb = (offsetsMsb & 7) << 29 >> 29;
680
+ const dopplerOffMsb = offsetsMsb >> 3 << 27 >> 27;
681
+ const codeOffLsb = view.getUint16(p + 6, true);
682
+ const carrierLsb2 = view.getUint16(p + 8, true);
683
+ const dopplerOffLsb = view.getUint16(p + 10, true);
684
+ let p2 = 0;
685
+ if (p1 !== 0 && (codeOffMsb !== -4 || codeOffLsb !== 0))
686
+ p2 = p1 + codeOffMsb * 65.536 + codeOffLsb * 1e-3;
687
+ let l2 = 0;
688
+ if (p2 !== 0 && freq2 > 0 && (carrierMsb2 !== -128 || carrierLsb2 !== 0))
689
+ l2 = p2 * freq2 / CLIGHT + carrierMsb2 * 65.536 + carrierLsb2 * 1e-3;
690
+ let d2 = null;
691
+ if (d1 !== null && freq1 > 0 && freq2 > 0 && (dopplerOffMsb !== -16 || dopplerOffLsb !== 0))
692
+ d2 = d1 * freq2 / freq1 + dopplerOffMsb * 6.5536 + dopplerOffLsb * 1e-4;
693
+ const cn02 = cn0Raw2 !== 255 ? cn0Raw2 * 0.25 + (sig2 === 1 || sig2 === 2 ? 0 : 10) : null;
694
+ curMeas.push({
695
+ prn,
696
+ sys,
697
+ code: code2,
698
+ freq: freq2,
699
+ pr: p2,
700
+ cp: l2,
701
+ cn0: cn02,
702
+ doppler: d2,
703
+ lockTimeMs: lock2 !== 255 ? lock2 * 1e3 : null
704
+ });
705
+ }
706
+ }
707
+ };
708
+ let i = 0;
709
+ while (i + 8 <= data.length) {
710
+ if (data[i] !== 36 || data[i + 1] !== 64) {
711
+ i++;
712
+ continue;
713
+ }
714
+ const len = view.getUint16(i + 6, true);
715
+ if (len < 8 || len % 4 !== 0) {
716
+ i++;
717
+ continue;
718
+ }
719
+ if (i + len > data.length) break;
720
+ if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
721
+ badCrc++;
722
+ i++;
723
+ continue;
724
+ }
725
+ const id = view.getUint16(i + 4, true) & 8191;
726
+ const key = String(id);
727
+ messageCounts[key] = (messageCounts[key] ?? 0) + 1;
728
+ if ((id === 4027 || id === 4109 || id === 4110 || id === 4111) && len >= 16) {
729
+ const tow = view.getUint32(i + 8, true);
730
+ const wnc = view.getUint16(i + 12, true);
731
+ if (tow !== 4294967295 && wnc !== 65535) {
732
+ ensureEpoch(GPS_EPOCH_MS + wnc * MS_PER_WEEK + tow);
733
+ if (id === 4109) decodeMeas3Ranges(i, tow);
734
+ else if (id === 4110) decodeMeas3CN0(i, len);
735
+ else if (id === 4111) decodeMeas3Doppler(i, len);
736
+ else decodeMeasEpoch(i, len);
737
+ }
738
+ }
739
+ i += len;
740
+ }
741
+ flush();
742
+ return { epochs, messageCounts, obsCodes, badCrc };
743
+ }
744
+ // Annotate the CommonJS export names for ESM import in node:
745
+ 0 && (module.exports = {
746
+ parseSbfMeas
747
+ });