gnss-js 1.14.1 → 1.15.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/{chunk-YIHO74OS.js → chunk-BEQSEJMU.js} +390 -67
- package/dist/{chunk-SWKWJEGY.js → chunk-I4UV45NT.js} +269 -15
- package/dist/index.cjs +671 -96
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -3
- package/dist/novatel.cjs +357 -14
- package/dist/novatel.d.cts +69 -1
- package/dist/novatel.d.ts +69 -1
- package/dist/novatel.js +11 -1
- package/dist/sbf.cjs +478 -68
- package/dist/sbf.d.cts +138 -1
- package/dist/sbf.d.ts +138 -1
- package/dist/sbf.js +9 -3
- package/package.json +1 -1
|
@@ -1,10 +1,270 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
|
+
getUtcDate
|
|
3
|
+
} from "./chunk-HVXYFUCB.js";
|
|
4
|
+
|
|
5
|
+
// src/novatel/frame.ts
|
|
6
|
+
var OEM4_HLEN = 28;
|
|
7
|
+
function crc32(data, start, len) {
|
|
8
|
+
let crc = 0;
|
|
9
|
+
for (let i = start; i < start + len; i++) {
|
|
10
|
+
crc ^= data[i];
|
|
11
|
+
for (let j = 0; j < 8; j++) {
|
|
12
|
+
crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return crc >>> 0;
|
|
16
|
+
}
|
|
17
|
+
function* oem4Frames(data, view, stats) {
|
|
18
|
+
let i = 0;
|
|
19
|
+
while (i + OEM4_HLEN + 4 <= data.length) {
|
|
20
|
+
if (data[i] !== 170 || data[i + 1] !== 68 || data[i + 2] !== 18) {
|
|
21
|
+
i++;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const hlen = data[i + 3];
|
|
25
|
+
const msgLen = view.getUint16(i + 8, true);
|
|
26
|
+
const total = hlen + msgLen + 4;
|
|
27
|
+
if (hlen < OEM4_HLEN || i + total > data.length) {
|
|
28
|
+
i++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (crc32(data, i, hlen + msgLen) !== view.getUint32(i + hlen + msgLen, true)) {
|
|
32
|
+
stats.badCrc++;
|
|
33
|
+
i++;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
yield {
|
|
37
|
+
id: view.getUint16(i + 4, true),
|
|
38
|
+
start: i,
|
|
39
|
+
payload: i + hlen,
|
|
40
|
+
msgLen,
|
|
41
|
+
binary: (data[i + 6] >> 4 & 3) === 0,
|
|
42
|
+
week: view.getUint16(i + 14, true),
|
|
43
|
+
towMs: view.getUint32(i + 16, true)
|
|
44
|
+
};
|
|
45
|
+
i += total;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/navbits/index.ts
|
|
50
|
+
var GPS_PI = 3.1415926535898;
|
|
2
51
|
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
52
|
+
var SEC_PER_WEEK = 7 * 86400;
|
|
53
|
+
function getBitU(buff, pos, len) {
|
|
54
|
+
let bits = 0;
|
|
55
|
+
for (let i = pos; i < pos + len; i++) {
|
|
56
|
+
bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
|
|
57
|
+
}
|
|
58
|
+
return bits;
|
|
59
|
+
}
|
|
60
|
+
function getBitS(buff, pos, len) {
|
|
61
|
+
const bits = getBitU(buff, pos, len);
|
|
62
|
+
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
63
|
+
return bits - 2 ** len;
|
|
64
|
+
}
|
|
65
|
+
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
66
|
+
if (subframes.length < 90) return null;
|
|
67
|
+
const b = subframes;
|
|
68
|
+
let i = 24;
|
|
69
|
+
const tow1 = getBitU(b, i, 17) * 6;
|
|
70
|
+
i += 17 + 2;
|
|
71
|
+
const id1 = getBitU(b, i, 3);
|
|
72
|
+
i += 3 + 2;
|
|
73
|
+
const week10 = getBitU(b, i, 10);
|
|
74
|
+
i += 10;
|
|
75
|
+
i += 2;
|
|
76
|
+
i += 4;
|
|
77
|
+
const svHealth = getBitU(b, i, 6);
|
|
78
|
+
i += 6;
|
|
79
|
+
const iodc0 = getBitU(b, i, 2);
|
|
80
|
+
i += 2;
|
|
81
|
+
i += 1 + 87;
|
|
82
|
+
const tgdRaw = getBitS(b, i, 8);
|
|
83
|
+
i += 8;
|
|
84
|
+
const iodc1 = getBitU(b, i, 8);
|
|
85
|
+
i += 8;
|
|
86
|
+
const tocSec = getBitU(b, i, 16) * 16;
|
|
87
|
+
i += 16;
|
|
88
|
+
const af2 = getBitS(b, i, 8) * 2 ** -55;
|
|
89
|
+
i += 8;
|
|
90
|
+
const af1 = getBitS(b, i, 16) * 2 ** -43;
|
|
91
|
+
i += 16;
|
|
92
|
+
const af0 = getBitS(b, i, 22) * 2 ** -31;
|
|
93
|
+
i = 240 + 24;
|
|
94
|
+
i += 17 + 2;
|
|
95
|
+
const id2 = getBitU(b, i, 3);
|
|
96
|
+
i += 3 + 2;
|
|
97
|
+
const iode = getBitU(b, i, 8);
|
|
98
|
+
i += 8;
|
|
99
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
100
|
+
i += 16;
|
|
101
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
102
|
+
i += 16;
|
|
103
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
104
|
+
i += 32;
|
|
105
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
106
|
+
i += 16;
|
|
107
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
108
|
+
i += 32;
|
|
109
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
110
|
+
i += 16;
|
|
111
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
112
|
+
i += 32;
|
|
113
|
+
const toes = getBitU(b, i, 16) * 16;
|
|
114
|
+
i = 480 + 24;
|
|
115
|
+
i += 17 + 2;
|
|
116
|
+
const id3 = getBitU(b, i, 3);
|
|
117
|
+
i += 3 + 2;
|
|
118
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
119
|
+
i += 16;
|
|
120
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
121
|
+
i += 32;
|
|
122
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
123
|
+
i += 16;
|
|
124
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
125
|
+
i += 32;
|
|
126
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
127
|
+
i += 16;
|
|
128
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
129
|
+
i += 32;
|
|
130
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
131
|
+
i += 24;
|
|
132
|
+
const iode3 = getBitU(b, i, 8);
|
|
133
|
+
i += 8;
|
|
134
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
135
|
+
const iodc = iodc0 * 256 + iodc1;
|
|
136
|
+
if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
|
|
137
|
+
if (iode3 !== iode || iode !== (iodc & 255)) return null;
|
|
138
|
+
const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS) / 1e3 / SEC_PER_WEEK);
|
|
139
|
+
let week = week10 + 1024 * Math.round((ref - week10) / 1024);
|
|
140
|
+
if (toes < tow1 - 302400) week++;
|
|
141
|
+
else if (toes > tow1 + 302400) week--;
|
|
142
|
+
const prn = opts.prn ?? "G00";
|
|
143
|
+
const tocDate = new Date(
|
|
144
|
+
GPS_EPOCH_MS + (week * SEC_PER_WEEK + tocSec) * 1e3
|
|
145
|
+
);
|
|
146
|
+
return {
|
|
147
|
+
system: prn[0] === "J" ? "J" : "G",
|
|
148
|
+
prn,
|
|
149
|
+
tocDate,
|
|
150
|
+
// Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
|
|
151
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK,
|
|
152
|
+
af0,
|
|
153
|
+
af1,
|
|
154
|
+
af2,
|
|
155
|
+
iode,
|
|
156
|
+
crs,
|
|
157
|
+
deltaN,
|
|
158
|
+
m0,
|
|
159
|
+
cuc,
|
|
160
|
+
e,
|
|
161
|
+
cus,
|
|
162
|
+
sqrtA,
|
|
163
|
+
toe: toes,
|
|
164
|
+
cic,
|
|
165
|
+
omega0,
|
|
166
|
+
cis,
|
|
167
|
+
i0,
|
|
168
|
+
crc,
|
|
169
|
+
omega,
|
|
170
|
+
omegaDot,
|
|
171
|
+
idot,
|
|
172
|
+
week,
|
|
173
|
+
svHealth,
|
|
174
|
+
tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
|
|
175
|
+
// IS-GPS-200: -128 reserved
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/novatel/nav.ts
|
|
180
|
+
var ID_RAWEPHEM = 41;
|
|
181
|
+
var ID_GLOEPHEMERIS = 723;
|
|
182
|
+
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
183
|
+
var SEC_PER_WEEK2 = 7 * 86400;
|
|
184
|
+
var SEC_PER_DAY = 86400;
|
|
185
|
+
function decodeRawEphem(data, view, p) {
|
|
186
|
+
const prn = view.getUint32(p, true);
|
|
187
|
+
if (prn < 1 || prn > 32) return null;
|
|
188
|
+
const refWeek = view.getUint32(p + 4, true);
|
|
189
|
+
return decodeGpsLnavFrame(data.subarray(p + 12, p + 102), {
|
|
190
|
+
prn: `G${String(prn).padStart(2, "0")}`,
|
|
191
|
+
refWeek
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function decodeGloEphemeris(view, p) {
|
|
195
|
+
const slot = view.getUint16(p, true) - 37;
|
|
196
|
+
if (slot < 1 || slot > 27) return null;
|
|
197
|
+
const freqNum = view.getUint16(p + 2, true) - 7;
|
|
198
|
+
const week = view.getUint16(p + 6, true);
|
|
199
|
+
const tow = Math.floor(view.getUint32(p + 8, true) / 1e3 + 0.5);
|
|
200
|
+
const toff = view.getUint32(p + 12, true);
|
|
201
|
+
const health = view.getUint32(p + 24, true) < 4 ? 0 : 1;
|
|
202
|
+
let tof = view.getUint32(p + 124, true) - toff;
|
|
203
|
+
tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
|
|
204
|
+
if (tof < tow - 43200) tof += SEC_PER_DAY;
|
|
205
|
+
else if (tof > tow + 43200) tof -= SEC_PER_DAY;
|
|
206
|
+
const toeGpsMs = GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tow) * 1e3;
|
|
207
|
+
const tofGpsMs = GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tof) * 1e3;
|
|
208
|
+
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS2) / 1e3;
|
|
209
|
+
return {
|
|
210
|
+
system: "R",
|
|
211
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
212
|
+
tocDate: getUtcDate(new Date(toeGpsMs)),
|
|
213
|
+
tauN: -view.getFloat64(p + 100, true),
|
|
214
|
+
// RINEX stores −τ_n
|
|
215
|
+
gammaN: view.getFloat64(p + 116, true),
|
|
216
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK2 + SEC_PER_WEEK2) % SEC_PER_WEEK2,
|
|
217
|
+
x: view.getFloat64(p + 28, true) / 1e3,
|
|
218
|
+
y: view.getFloat64(p + 36, true) / 1e3,
|
|
219
|
+
z: view.getFloat64(p + 44, true) / 1e3,
|
|
220
|
+
xDot: view.getFloat64(p + 52, true) / 1e3,
|
|
221
|
+
yDot: view.getFloat64(p + 60, true) / 1e3,
|
|
222
|
+
zDot: view.getFloat64(p + 68, true) / 1e3,
|
|
223
|
+
xAcc: view.getFloat64(p + 76, true) / 1e3,
|
|
224
|
+
yAcc: view.getFloat64(p + 84, true) / 1e3,
|
|
225
|
+
zAcc: view.getFloat64(p + 92, true) / 1e3,
|
|
226
|
+
health,
|
|
227
|
+
freqNum
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function parseNovatelNav(data) {
|
|
231
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
232
|
+
const stats = { badCrc: 0 };
|
|
233
|
+
const ephemerides = [];
|
|
234
|
+
const lastGps = /* @__PURE__ */ new Map();
|
|
235
|
+
const lastGlo = /* @__PURE__ */ new Map();
|
|
236
|
+
for (const frame of oem4Frames(data, view, stats)) {
|
|
237
|
+
if (!frame.binary) continue;
|
|
238
|
+
if (frame.id === ID_RAWEPHEM && frame.msgLen >= 102) {
|
|
239
|
+
const eph = decodeRawEphem(data, view, frame.payload);
|
|
240
|
+
if (!eph) continue;
|
|
241
|
+
const prev = lastGps.get(eph.prn);
|
|
242
|
+
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
lastGps.set(eph.prn, eph);
|
|
246
|
+
ephemerides.push(eph);
|
|
247
|
+
} else if (frame.id === ID_GLOEPHEMERIS && frame.msgLen >= 144) {
|
|
248
|
+
const eph = decodeGloEphemeris(view, frame.payload);
|
|
249
|
+
if (!eph) continue;
|
|
250
|
+
const prev = lastGlo.get(eph.prn);
|
|
251
|
+
if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
lastGlo.set(eph.prn, eph);
|
|
255
|
+
ephemerides.push(eph);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return { ephemerides, badCrc: stats.badCrc };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/novatel/index.ts
|
|
262
|
+
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
3
263
|
var MS_PER_WEEK = 7 * 864e5;
|
|
4
264
|
var HDR = 28;
|
|
5
265
|
var ID_RANGE = 43;
|
|
6
266
|
var ID_RANGECMP = 140;
|
|
7
|
-
var
|
|
267
|
+
var ID_GLOEPHEMERIS2 = 723;
|
|
8
268
|
var C_LIGHT = 299792458;
|
|
9
269
|
var ADR_ROLL = 8388608;
|
|
10
270
|
function carrierFreq(sys, code, gloK) {
|
|
@@ -32,16 +292,6 @@ function carrierFreq(sys, code, gloK) {
|
|
|
32
292
|
function exsign(v, bits) {
|
|
33
293
|
return v & 1 << bits - 1 ? v - 2 ** bits : v;
|
|
34
294
|
}
|
|
35
|
-
function crc32(data, start, len) {
|
|
36
|
-
let crc = 0;
|
|
37
|
-
for (let i = start; i < start + len; i++) {
|
|
38
|
-
crc ^= data[i];
|
|
39
|
-
for (let j = 0; j < 8; j++) {
|
|
40
|
-
crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return crc >>> 0;
|
|
44
|
-
}
|
|
45
295
|
var SIGNALS = {
|
|
46
296
|
0: {
|
|
47
297
|
0: ["G", "1C"],
|
|
@@ -95,7 +345,7 @@ function parseNovatelRange(data) {
|
|
|
95
345
|
const hl = data[j + 3];
|
|
96
346
|
const id = view.getUint16(j + 4, true);
|
|
97
347
|
const ln = view.getUint16(j + 8, true);
|
|
98
|
-
if (id !==
|
|
348
|
+
if (id !== ID_GLOEPHEMERIS2 || hl < HDR || j + hl + ln + 4 > data.length)
|
|
99
349
|
continue;
|
|
100
350
|
if (crc32(data, j, hl + ln) !== view.getUint32(j + hl + ln, true)) continue;
|
|
101
351
|
const slot = view.getUint16(j + hl, true) - 37;
|
|
@@ -179,7 +429,7 @@ function parseNovatelRange(data) {
|
|
|
179
429
|
if (!codes.includes(code)) codes.push(code);
|
|
180
430
|
}
|
|
181
431
|
epochs.push({
|
|
182
|
-
timeMs:
|
|
432
|
+
timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + towMs,
|
|
183
433
|
meas
|
|
184
434
|
});
|
|
185
435
|
}
|
|
@@ -231,7 +481,7 @@ function parseNovatelRange(data) {
|
|
|
231
481
|
if (!codes.includes(code)) codes.push(code);
|
|
232
482
|
}
|
|
233
483
|
epochs.push({
|
|
234
|
-
timeMs:
|
|
484
|
+
timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + towMs,
|
|
235
485
|
meas
|
|
236
486
|
});
|
|
237
487
|
}
|
|
@@ -242,5 +492,9 @@ function parseNovatelRange(data) {
|
|
|
242
492
|
}
|
|
243
493
|
|
|
244
494
|
export {
|
|
495
|
+
OEM4_HLEN,
|
|
496
|
+
crc32,
|
|
497
|
+
oem4Frames,
|
|
498
|
+
parseNovatelNav,
|
|
245
499
|
parseNovatelRange
|
|
246
500
|
};
|