gnss-js 1.17.0 → 1.19.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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  decodeGpsLnavFrame
3
- } from "./chunk-REYOYF7O.js";
3
+ } from "./chunk-IQ5OIMQD.js";
4
4
  import {
5
5
  getUtcDate
6
6
  } from "./chunk-HVXYFUCB.js";
@@ -55,6 +55,7 @@ var ID_RAWEPHEM = 41;
55
55
  var ID_GLOEPHEMERIS = 723;
56
56
  var ID_GALEPHEMERIS = 1122;
57
57
  var ID_QZSSEPHEMERIS = 1336;
58
+ var ID_GPSEPHEM = 7;
58
59
  var ID_BDSEPHEMERIS = 1696;
59
60
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
60
61
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
@@ -209,9 +210,10 @@ function decodeBdsEphemeris(view, p) {
209
210
  // TGD1 (B1) — RINEX slot
210
211
  };
211
212
  }
212
- function decodeQzssEphemeris(view, p) {
213
+ function decodeGpsQzssEphemeris(view, p, sys) {
213
214
  const prn = view.getUint32(p, true);
214
- if (prn < 193 || prn > 202) return null;
215
+ if (sys === "G" && (prn < 1 || prn > 32)) return null;
216
+ if (sys === "J" && (prn < 193 || prn > 202)) return null;
215
217
  const health = view.getUint32(p + 12, true) & 63;
216
218
  const iode1 = view.getUint32(p + 16, true);
217
219
  const week = view.getUint32(p + 24, true);
@@ -220,8 +222,8 @@ function decodeQzssEphemeris(view, p) {
220
222
  const tocs = view.getFloat64(p + 164, true);
221
223
  const tocDate = new Date(nearWeekMs(toeMs, tocs));
222
224
  return {
223
- system: "J",
224
- prn: `J${String(prn - 192).padStart(2, "0")}`,
225
+ system: sys,
226
+ prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
225
227
  toc: sowOf(tocDate.getTime()),
226
228
  tocDate,
227
229
  af0: view.getFloat64(p + 180, true),
@@ -279,8 +281,11 @@ function parseNovatelNav(data) {
279
281
  } else if (frame.id === ID_BDSEPHEMERIS && frame.msgLen >= 196) {
280
282
  const eph = decodeBdsEphemeris(view, frame.payload);
281
283
  if (eph) pushKepler(eph.prn, eph);
284
+ } else if (frame.id === ID_GPSEPHEM && frame.msgLen >= 204) {
285
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "G");
286
+ if (eph) pushKepler(eph.prn, eph);
282
287
  } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
283
- const eph = decodeQzssEphemeris(view, frame.payload);
288
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
284
289
  if (eph) pushKepler(eph.prn, eph);
285
290
  } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
286
291
  const p = frame.payload;
@@ -1,3 +1,7 @@
1
+ import {
2
+ CnavAssembler,
3
+ cnavCrcOk
4
+ } from "./chunk-6NCMACDO.js";
1
5
  import {
2
6
  getGpsLeap
3
7
  } from "./chunk-HVXYFUCB.js";
@@ -404,6 +408,42 @@ function parseSbfIonoUtc(data) {
404
408
  return { ionoCorrections, leapSeconds };
405
409
  }
406
410
 
411
+ // src/sbf/rawnav.ts
412
+ var SIGNAL_OF_BLOCK = {
413
+ 4018: "L2C",
414
+ 4019: "L5"
415
+ };
416
+ function parseSbfCnav(data) {
417
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
418
+ const ephemerides = [];
419
+ const assemblers = {
420
+ L2C: new CnavAssembler(),
421
+ L5: new CnavAssembler()
422
+ };
423
+ let badCrc = 0;
424
+ let messages = 0;
425
+ scanSbfFrames(data, view, (id, b, len) => {
426
+ const signal = SIGNAL_OF_BLOCK[id];
427
+ if (!signal || len < 60) return;
428
+ messages++;
429
+ const msg = new Uint8Array(40);
430
+ for (let k = 0; k < 10; k++) {
431
+ const w = view.getUint32(b + 20 + 4 * k, true);
432
+ msg[4 * k] = w >>> 24;
433
+ msg[4 * k + 1] = w >>> 16 & 255;
434
+ msg[4 * k + 2] = w >>> 8 & 255;
435
+ msg[4 * k + 3] = w & 255;
436
+ }
437
+ if (!cnavCrcOk(msg)) {
438
+ badCrc++;
439
+ return;
440
+ }
441
+ const eph = assemblers[signal].push(msg);
442
+ if (eph) ephemerides.push({ ...eph, signal });
443
+ });
444
+ return { ephemerides, badCrc, messages };
445
+ }
446
+
407
447
  // src/sbf/index.ts
408
448
  var CLIGHT = 299792458;
409
449
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
@@ -1078,5 +1118,6 @@ export {
1078
1118
  parseSbfNav,
1079
1119
  parseSbfAlmanac,
1080
1120
  parseSbfIonoUtc,
1121
+ parseSbfCnav,
1081
1122
  parseSbfMeas
1082
1123
  };
@@ -0,0 +1,208 @@
1
+ import {
2
+ GPS_PI,
3
+ getBitS,
4
+ getBitU
5
+ } from "./chunk-IQ5OIMQD.js";
6
+
7
+ // src/navbits/cnav.ts
8
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
9
+ var SEC_PER_WEEK = 7 * 86400;
10
+ var HALF_WEEK = 302400;
11
+ var CNAV_PREAMBLE = 139;
12
+ var CNAV_A_REF = 26559710;
13
+ var CNAV_OMEGA_DOT_REF = -26e-10;
14
+ function crc24q(buff, bitLen) {
15
+ let crc = 0;
16
+ for (let i = 0; i < bitLen; i++) {
17
+ crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
18
+ const msb = crc & 8388608;
19
+ crc = crc << 1 & 16777215;
20
+ if (msb) crc ^= 8801531;
21
+ }
22
+ return crc;
23
+ }
24
+ function cnavCrcOk(msg) {
25
+ if (msg.length < 38) return false;
26
+ return crc24q(msg, 276) === getBitU(msg, 276, 24);
27
+ }
28
+ function getBitU33(b, pos) {
29
+ return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
30
+ }
31
+ function getBitS33(b, pos) {
32
+ const u = getBitU33(b, pos);
33
+ return u < 2 ** 32 ? u : u - 2 ** 33;
34
+ }
35
+ function decodeType10(b, tow) {
36
+ return {
37
+ tow,
38
+ week: getBitU(b, 38, 13),
39
+ health: getBitU(b, 51, 3),
40
+ top: getBitU(b, 54, 11) * 300,
41
+ uraEd: getBitS(b, 65, 5),
42
+ toe: getBitU(b, 70, 11) * 300,
43
+ deltaA: getBitS(b, 81, 26) * 2 ** -9,
44
+ aDot: getBitS(b, 107, 25) * 2 ** -21,
45
+ deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
46
+ deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
47
+ m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
48
+ e: getBitU33(b, 205) * 2 ** -34,
49
+ omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
50
+ integrityFlag: getBitU(b, 271, 1) === 1,
51
+ l2cPhasing: getBitU(b, 272, 1) === 1
52
+ };
53
+ }
54
+ function decodeType11(b) {
55
+ return {
56
+ toe: getBitU(b, 38, 11) * 300,
57
+ omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
58
+ i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
59
+ deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
60
+ i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
61
+ cis: getBitS(b, 147, 16) * 2 ** -30,
62
+ cic: getBitS(b, 163, 16) * 2 ** -30,
63
+ crs: getBitS(b, 179, 24) * 2 ** -8,
64
+ crc: getBitS(b, 203, 24) * 2 ** -8,
65
+ cus: getBitS(b, 227, 21) * 2 ** -30,
66
+ cuc: getBitS(b, 248, 21) * 2 ** -30
67
+ };
68
+ }
69
+ var isc = (b, pos) => {
70
+ const raw = getBitS(b, pos, 13);
71
+ return raw === -4096 ? null : raw * 2 ** -35;
72
+ };
73
+ function decodeClock(b, msgType) {
74
+ const clock = {
75
+ msgType,
76
+ top: getBitU(b, 38, 11) * 300,
77
+ uraNed0: getBitS(b, 49, 5),
78
+ uraNed1: getBitU(b, 54, 3),
79
+ uraNed2: getBitU(b, 57, 3),
80
+ toc: getBitU(b, 60, 11) * 300,
81
+ af0: getBitS(b, 71, 26) * 2 ** -35,
82
+ af1: getBitS(b, 97, 20) * 2 ** -48,
83
+ af2: getBitS(b, 117, 10) * 2 ** -60
84
+ };
85
+ if (msgType === 30) {
86
+ clock.tgd = isc(b, 127);
87
+ clock.iscL1ca = isc(b, 140);
88
+ clock.iscL2c = isc(b, 153);
89
+ clock.iscL5i5 = isc(b, 166);
90
+ clock.iscL5q5 = isc(b, 179);
91
+ clock.ionoAlpha = [
92
+ getBitS(b, 192, 8) * 2 ** -30,
93
+ getBitS(b, 200, 8) * 2 ** -27,
94
+ getBitS(b, 208, 8) * 2 ** -24,
95
+ getBitS(b, 216, 8) * 2 ** -24
96
+ ];
97
+ clock.ionoBeta = [
98
+ getBitS(b, 224, 8) * 2 ** 11,
99
+ getBitS(b, 232, 8) * 2 ** 14,
100
+ getBitS(b, 240, 8) * 2 ** 16,
101
+ getBitS(b, 248, 8) * 2 ** 16
102
+ ];
103
+ clock.wnOp = getBitU(b, 256, 8);
104
+ }
105
+ return clock;
106
+ }
107
+ function resolveWeek(week, towSec, sec) {
108
+ if (sec < towSec - HALF_WEEK) return week + 1;
109
+ if (sec > towSec + HALF_WEEK) return week - 1;
110
+ return week;
111
+ }
112
+ function gpsDate(week, sec) {
113
+ return new Date(GPS_EPOCH_MS + (week * SEC_PER_WEEK + sec) * 1e3);
114
+ }
115
+ var CnavAssembler = class {
116
+ sats = /* @__PURE__ */ new Map();
117
+ /**
118
+ * Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
119
+ * the preamble). Returns the newly completed ephemeris, or null.
120
+ * Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
121
+ * are out of range, are ignored.
122
+ */
123
+ push(msg) {
124
+ if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
125
+ const prn = getBitU(msg, 8, 6);
126
+ if (prn < 1 || prn > 32) return null;
127
+ const type = getBitU(msg, 14, 6);
128
+ const tow = getBitU(msg, 20, 17) * 6;
129
+ let sat = this.sats.get(prn);
130
+ if (!sat) {
131
+ sat = {};
132
+ this.sats.set(prn, sat);
133
+ }
134
+ if (type === 10) sat.t10 = decodeType10(msg, tow);
135
+ else if (type === 11) sat.t11 = decodeType11(msg);
136
+ else if (type >= 30 && type <= 37) {
137
+ sat.clock = decodeClock(msg, type);
138
+ if (type === 30) sat.extras = sat.clock;
139
+ } else return null;
140
+ return this.tryEmit(prn, sat);
141
+ }
142
+ tryEmit(prn, sat) {
143
+ const { t10, t11, clock, extras } = sat;
144
+ if (!t10 || !t11 || !clock) return null;
145
+ if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
146
+ const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
147
+ if (key === sat.lastKey) return null;
148
+ sat.lastKey = key;
149
+ const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
150
+ const a = CNAV_A_REF + t10.deltaA;
151
+ return {
152
+ system: "G",
153
+ prn: `G${String(prn).padStart(2, "0")}`,
154
+ week: t10.week,
155
+ health: t10.health,
156
+ uraEd: t10.uraEd,
157
+ uraNed0: clock.uraNed0,
158
+ uraNed1: clock.uraNed1,
159
+ uraNed2: clock.uraNed2,
160
+ top: t10.top,
161
+ toe: t10.toe,
162
+ toeDate: gpsDate(weekToe, t10.toe),
163
+ a,
164
+ deltaA: t10.deltaA,
165
+ aDot: t10.aDot,
166
+ deltaN0: t10.deltaN0,
167
+ deltaN0Dot: t10.deltaN0Dot,
168
+ m0: t10.m0,
169
+ e: t10.e,
170
+ omega: t10.omega,
171
+ omega0: t11.omega0,
172
+ i0: t11.i0,
173
+ omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
174
+ deltaOmegaDot: t11.deltaOmegaDot,
175
+ i0Dot: t11.i0Dot,
176
+ cis: t11.cis,
177
+ cic: t11.cic,
178
+ crs: t11.crs,
179
+ crc: t11.crc,
180
+ cus: t11.cus,
181
+ cuc: t11.cuc,
182
+ toc: clock.toc,
183
+ tocDate: gpsDate(weekToe, clock.toc),
184
+ af0: clock.af0,
185
+ af1: clock.af1,
186
+ af2: clock.af2,
187
+ clockMsgType: clock.msgType,
188
+ tgd: extras?.tgd ?? null,
189
+ iscL1ca: extras?.iscL1ca ?? null,
190
+ iscL2c: extras?.iscL2c ?? null,
191
+ iscL5i5: extras?.iscL5i5 ?? null,
192
+ iscL5q5: extras?.iscL5q5 ?? null,
193
+ ...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
194
+ ...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
195
+ ...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
196
+ integrityFlag: t10.integrityFlag,
197
+ l2cPhasing: t10.l2cPhasing,
198
+ tow: t10.tow
199
+ };
200
+ }
201
+ };
202
+
203
+ export {
204
+ CNAV_A_REF,
205
+ CNAV_OMEGA_DOT_REF,
206
+ cnavCrcOk,
207
+ CnavAssembler
208
+ };
@@ -140,6 +140,7 @@ function decodeGpsLnavFrame(subframes, opts = {}) {
140
140
  }
141
141
 
142
142
  export {
143
+ GPS_PI,
143
144
  getBitU,
144
145
  getBitS,
145
146
  setBitU,
@@ -1,9 +1,13 @@
1
+ import {
2
+ CnavAssembler,
3
+ cnavCrcOk
4
+ } from "./chunk-6NCMACDO.js";
1
5
  import {
2
6
  decodeGpsLnavFrame,
3
7
  getBitS,
4
8
  getBitU,
5
9
  setBitU
6
- } from "./chunk-REYOYF7O.js";
10
+ } from "./chunk-IQ5OIMQD.js";
7
11
 
8
12
  // src/ubx/frame.ts
9
13
  function* ubxFrames(data, stats = { badChecksums: 0 }) {
@@ -144,6 +148,40 @@ function parseUbxIonoUtc(data) {
144
148
  return { ionoCorrections, leapSeconds };
145
149
  }
146
150
 
151
+ // src/ubx/cnav.ts
152
+ function parseUbxCnav(data) {
153
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
154
+ const assembler = new CnavAssembler();
155
+ const ephemerides = [];
156
+ let badCrc = 0;
157
+ let messages = 0;
158
+ for (const f of ubxFrames(data)) {
159
+ if (f.msgClass !== 2 || f.msgId !== 19) continue;
160
+ const p = f.payload;
161
+ if (p.length < 8 + 40) continue;
162
+ if (p[0] !== 0 || p[2] !== 3 && p[2] !== 4) continue;
163
+ const svId = p[1];
164
+ if (svId < 1 || svId > 32) continue;
165
+ messages++;
166
+ const msg = new Uint8Array(40);
167
+ const base = f.payloadStart + 8;
168
+ for (let k = 0; k < 10; k++) {
169
+ const w = view.getUint32(base + 4 * k, true);
170
+ msg[4 * k] = w >>> 24;
171
+ msg[4 * k + 1] = w >>> 16 & 255;
172
+ msg[4 * k + 2] = w >>> 8 & 255;
173
+ msg[4 * k + 3] = w & 255;
174
+ }
175
+ if (!cnavCrcOk(msg)) {
176
+ badCrc++;
177
+ continue;
178
+ }
179
+ const eph = assembler.push(msg);
180
+ if (eph) ephemerides.push(eph);
181
+ }
182
+ return { ephemerides, badCrc, messages };
183
+ }
184
+
147
185
  // src/ubx/index.ts
148
186
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
149
187
  var MS_PER_WEEK = 7 * 864e5;
@@ -241,5 +279,6 @@ export {
241
279
  ubxFrames,
242
280
  parseUbxNav,
243
281
  parseUbxIonoUtc,
282
+ parseUbxCnav,
244
283
  parseUbxRawx
245
284
  };