/src/gpsd/gpsd-3.27.6~dev/drivers/driver_skytraq.c
Line | Count | Source |
1 | | /* |
2 | | * This is the gpsd driver for Skytraq GPSes operating in binary mode. |
3 | | * |
4 | | * SkyTraq is Big Endian |
5 | | * |
6 | | * This file is Copyright by the GPSD project |
7 | | * SPDX-License-Identifier: BSD-2-clause |
8 | | */ |
9 | | |
10 | | #include "../include/gpsd_config.h" // must be before all includes |
11 | | |
12 | | #include <ctype.h> |
13 | | #include <math.h> |
14 | | #include <stdbool.h> |
15 | | #include <stdio.h> |
16 | | #include <stdlib.h> |
17 | | #include <string.h> // for strlcpy() |
18 | | #include <strings.h> |
19 | | #include <unistd.h> |
20 | | |
21 | | #include "../include/gpsd.h" |
22 | | #include "../include/bits.h" |
23 | | #include "../include/strfuncs.h" |
24 | | #if defined(SKYTRAQ_ENABLE) |
25 | | #include "../include/timespec.h" |
26 | | |
27 | | #define HI(n) ((n) >> 8) |
28 | | #define LO(n) ((n) & 0xff) |
29 | | |
30 | | /* |
31 | | * No ACK/NAK? Just retry after 6 seconds |
32 | | */ |
33 | | #define SKY_RETRY_TIME 6 |
34 | | // Phoenix has 230 channels |
35 | 1.32k | #define SKY_CHANNELS 230 // max channels allowed in format |
36 | | |
37 | | #ifdef __UNUSED |
38 | | // Poll Software Version MID 2 |
39 | | static unsigned char versionprobe[] = { |
40 | | 0xa0, 0xa1, 0x00, 0x02, |
41 | | 0x02, // MID 2 |
42 | | 0x01, // System |
43 | | 0x00, 0x0d, 0x0a |
44 | | }; |
45 | | #endif // __UNUSED |
46 | | |
47 | | /* place checksum into msg, write to device |
48 | | * Return: number of bytes written |
49 | | * negative on error |
50 | | */ |
51 | | static ssize_t sky_write(struct gps_device_t *session, char *msg, |
52 | | const size_t data_len) |
53 | 2.66k | { |
54 | 2.66k | uint8_t chk; |
55 | 2.66k | uint16_t len; |
56 | 2.66k | ssize_t i; |
57 | 2.66k | bool ok; |
58 | 2.66k | unsigned type = (unsigned)msg[4]; |
59 | 2.66k | uint8_t buf[BUFSIZ]; |
60 | 2.66k | uint8_t outbuf[BUFSIZ]; |
61 | | |
62 | | // do not write if -b (readonly) option set |
63 | | // "passive" handled earlier |
64 | 2.66k | if (session->context->readonly) { |
65 | 522 | return data_len; |
66 | 522 | } |
67 | | |
68 | 2.14k | if (sizeof(buf) <= data_len) { |
69 | | // uh, oh; |
70 | 0 | return -1; |
71 | 0 | } |
72 | | // make a copy, so we can edit it |
73 | 2.14k | memcpy(buf, msg, data_len); |
74 | | |
75 | | // max length is undocumented, largest I could find is 261 |
76 | 2.14k | len = (buf[2] << 8) | buf[3]; |
77 | | // limit to 512 to pacify coverity |
78 | 2.14k | if (512 < len) { |
79 | 0 | len = 512; |
80 | 0 | } |
81 | 2.14k | if ((size_t)(len + 7) != data_len) { |
82 | | // uh, oh; |
83 | 0 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
84 | 0 | "Skytraq: Length error: len %u data_len %zu buf %s\n", |
85 | 0 | len, data_len, |
86 | 0 | gps_hexdump((char *)outbuf, sizeof(outbuf), |
87 | 0 | buf, data_len)); |
88 | 0 | return -2; |
89 | 0 | } |
90 | | |
91 | | // calculate Checksum |
92 | 2.14k | chk = 0; |
93 | | // coverity_submit[tainted_data] |
94 | 5.51k | for (i = 0; i < len; i++) { |
95 | 3.36k | chk ^= buf[4 + i]; |
96 | 3.36k | } |
97 | | |
98 | | // enter checksum after payload |
99 | 2.14k | buf[len + 4] = chk; |
100 | 2.14k | len += 7; |
101 | | |
102 | 2.14k | GPSD_LOG(LOG_IO, &session->context->errout, |
103 | 2.14k | "Skytraq: Writing control MID %02x: %s\n", type, |
104 | 2.14k | gps_hexdump((char *)outbuf, sizeof(outbuf), buf, len)); |
105 | 2.14k | ok = gpsd_write(session, (const char *)buf, len) == len; |
106 | | |
107 | 2.14k | return ok; |
108 | 2.14k | } |
109 | | |
110 | | /* sky_mode() - NMEA/Binary mode changer |
111 | | * return: void |
112 | | * |
113 | | * Cherry-picked from: |
114 | | * 0004-Update-Skytraq-driver-to-support-Venus8-modules-chan.patch |
115 | | * by Kai Harrekilde-Petersen in: |
116 | | * https://lists.gnu.org/archive/html/gpsd-dev/2018-03/msg00025.html |
117 | | */ |
118 | | static void sky_mode(struct gps_device_t *session, int mode) |
119 | 0 | { |
120 | 0 | char msg[] = { |
121 | 0 | 0xA0, 0xA1, // start-of-sentence sequence |
122 | 0 | 0x00, 0x03, |
123 | 0 | 0x09, // SKY_CONFIG_MSG_TYPE |
124 | 0 | 0x00, 0x00, 0x00, |
125 | 0 | 0x0D, 0x0A // end-of-sentence sequence |
126 | 0 | }; |
127 | 0 | if (MODE_BINARY == mode) { |
128 | 0 | msg[5] = 0x02; |
129 | 0 | } else { // else to MODE_NMEA |
130 | 0 | msg[5] = 0x01; |
131 | 0 | } |
132 | |
|
133 | 0 | GPSD_LOG(LOG_PROG, &session->context->errout, |
134 | 0 | "Skytraq: setting MODE %s\n", |
135 | 0 | (MODE_BINARY == mode) ? "Binary" : "NMEA"); |
136 | 0 | (void)sky_write(session, msg, 10); |
137 | 0 | } |
138 | | |
139 | | /* |
140 | | * Convert PRN to gnssid and svid |
141 | | * |
142 | | * svId is always 0 to 99. |
143 | | */ |
144 | | static void PRN2_gnssId_svId(short PRN, uint8_t *gnssId, uint8_t *svId) |
145 | 7.82k | { |
146 | | // fit into gnssid:svid |
147 | 7.82k | if (0 == PRN) { |
148 | | // skip 0 PRN |
149 | 911 | *gnssId = 0; |
150 | 911 | *svId = 0; |
151 | 6.91k | } else if ((1 <= PRN) && |
152 | 6.91k | (32 >= PRN)) { |
153 | | // GPS |
154 | 1.05k | *gnssId = 0; |
155 | 1.05k | *svId = PRN; |
156 | 5.86k | } else if ((65 <= PRN) && |
157 | 5.03k | (96 >= PRN)) { |
158 | | // GLONASS |
159 | 1.20k | *gnssId = 6; |
160 | 1.20k | *svId = PRN - 64; |
161 | 4.66k | } else if ((120 <= PRN) && |
162 | 3.26k | (158 >= PRN)) { |
163 | | // SBAS |
164 | 655 | *gnssId = 1; |
165 | 655 | *svId = PRN; |
166 | 4.00k | } else if ((201 <= PRN) && |
167 | 2.01k | (239 >= PRN)) { |
168 | | // BeiDou |
169 | 764 | *gnssId = 3; |
170 | 764 | *svId = PRN - 200; |
171 | 3.24k | } else if ((240 <= PRN) && |
172 | 1.25k | (254 >= PRN)) { |
173 | | // IRNSS |
174 | 571 | *gnssId = 20; |
175 | 571 | *svId = PRN - 240; |
176 | 2.67k | } else { |
177 | | // huh? |
178 | 2.67k | *gnssId = 0; |
179 | 2.67k | *svId = 0; |
180 | 2.67k | } |
181 | 7.82k | return; |
182 | 7.82k | } |
183 | | |
184 | | /* |
185 | | decode MID 0x62 -- super packet |
186 | | * |
187 | | * Present in Phoenix |
188 | | */ |
189 | | static gps_mask_t sky_msg_62(struct gps_device_t *session, |
190 | | const unsigned char *buf, const size_t len) |
191 | 589 | { |
192 | 589 | unsigned sid; |
193 | 589 | unsigned u[23]; |
194 | 589 | int i; |
195 | | |
196 | 589 | if (3 > len) { |
197 | 141 | GPSD_LOG(LOG_WARN, &session->context->errout, |
198 | 141 | "Skytraq 0x62: bad len %zu\n", len); |
199 | 141 | return 0; |
200 | 141 | } |
201 | | |
202 | 448 | sid = getub(buf, 1); |
203 | 448 | switch (sid) { |
204 | 104 | case 0x80: |
205 | | // SBAS status |
206 | 104 | if (8 < len) { |
207 | 103 | GPSD_LOG(LOG_WARN, &session->context->errout, |
208 | 103 | "Skytraq 0x62/80: bad len %zu\n", len); |
209 | 103 | return 0; |
210 | 103 | } |
211 | 7 | for (i = 0; i < 6; i++) { |
212 | 6 | u[i] = getub(buf, i + 2); |
213 | 6 | } |
214 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
215 | 1 | "Skytraq 0x62/80: enable %u ranging %u URA mask %u " |
216 | 1 | "correction %u chans %u subsystems %u \n", |
217 | 1 | u[0], u[1], u[2], u[3], u[4], u[5]); |
218 | 1 | break; |
219 | 35 | case 0x81: |
220 | | // QXSS status |
221 | 35 | u[0] = getub(buf, 2); |
222 | 35 | u[1] = getub(buf, 3); |
223 | 35 | GPSD_LOG(LOG_PROG, &session->context->errout, |
224 | 35 | "Skytraq 0x62/81: enable %u chans %u\n", |
225 | 35 | u[0], u[1]); |
226 | 35 | break; |
227 | 70 | case 0x82: |
228 | | // SBAS advanced status |
229 | 70 | if (46 < len) { |
230 | 2 | GPSD_LOG(LOG_WARN, &session->context->errout, |
231 | 2 | "Skytraq 0x62/82: bad len %zu\n", len); |
232 | 2 | return 0; |
233 | 2 | } |
234 | 1.56k | for (i = 0; i < 22; i++) { |
235 | 1.49k | u[i] = getub(buf, i + 2); |
236 | 1.49k | } |
237 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
238 | 68 | "Skytraq 0x62/82: enable %u ranging %u URA %u corr %u " |
239 | 68 | "chans %u mask x%02x WAAS %u %u %u %u " |
240 | 68 | "EGNOS %u %u %u %u MSAS %u %u %u %u " |
241 | 68 | "GAGAN %u %u %u %u\n", |
242 | 68 | u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], |
243 | 68 | u[9], u[10], u[11], u[12], u[13], u[14], u[15], u[16], u[17], |
244 | 68 | u[18], u[19], u[20], u[21]); |
245 | 68 | break; |
246 | 239 | default: |
247 | 239 | GPSD_LOG(LOG_PROG, &session->context->errout, |
248 | 448 | "Skytraq 0x62: SID x%02x len %zu\n", sid, len); |
249 | 448 | } |
250 | 343 | return 0; |
251 | 448 | } |
252 | | |
253 | | /* |
254 | | * decode MID 0x63 -- super packet |
255 | | * |
256 | | * Present in Phoenix |
257 | | */ |
258 | | static gps_mask_t sky_msg_63(struct gps_device_t *session, |
259 | | const unsigned char *buf, const size_t len) |
260 | 696 | { |
261 | 696 | unsigned sid; |
262 | | |
263 | 696 | if (3 > len) { |
264 | 599 | GPSD_LOG(LOG_WARN, &session->context->errout, |
265 | 599 | "Skytraq 0x63: bad len %zu\n", len); |
266 | 599 | return 0; |
267 | 599 | } |
268 | | |
269 | 97 | sid = getub(buf, 1); |
270 | | |
271 | | // FIXME: decode them! |
272 | 97 | GPSD_LOG(LOG_PROG, &session->context->errout, |
273 | 97 | "Skytraq 0x63: SID %u\n", sid); |
274 | 97 | return 0; |
275 | 696 | } |
276 | | |
277 | | /* |
278 | | * decode MID 0x64 -- super packet |
279 | | * |
280 | | * Present in Phoenix |
281 | | */ |
282 | | static gps_mask_t sky_msg_64(struct gps_device_t *session, |
283 | | const unsigned char *buf, const size_t len) |
284 | 1.05k | { |
285 | 1.05k | unsigned sid; |
286 | 1.05k | unsigned u[13]; |
287 | 1.05k | int i; |
288 | 1.05k | int s[3]; |
289 | | |
290 | 1.05k | if (3 > len) { |
291 | 70 | GPSD_LOG(LOG_WARN, &session->context->errout, |
292 | 70 | "Skytraq 0x64: bad len %zu\n", len); |
293 | 70 | return 0; |
294 | 70 | } |
295 | | |
296 | 984 | sid = getub(buf, 1); |
297 | 984 | switch (sid) { |
298 | 104 | case 0x80: |
299 | | // GNSS Boot status |
300 | 104 | u[0] = getub(buf, 2); |
301 | 104 | u[1] = getub(buf, 3); |
302 | 104 | GPSD_LOG(LOG_PROG, &session->context->errout, |
303 | 104 | "Skytraq 0x64/80: enable %u type %u\n", |
304 | 104 | u[0], u[1]); |
305 | 104 | break; |
306 | 136 | case 0x81: |
307 | | // Extended NMEA Message Interval |
308 | 136 | if (14 > len) { |
309 | 68 | GPSD_LOG(LOG_WARN, &session->context->errout, |
310 | 68 | "Skytraq 0x64/81: bad len %zu\n", len); |
311 | 68 | return 0; |
312 | 68 | } |
313 | 884 | for (i = 0; i < 12; i++) { |
314 | 816 | u[i] = getub(buf, i + 2); |
315 | 816 | } |
316 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
317 | 68 | "Skytraq 0x64/81: GGA %u GSA %u GSV %u GLL %u RMC %u " |
318 | 68 | "VTG %u ZDA %u GNS %u GBS %u GRS %u DTM %u GST %u\n", |
319 | 68 | u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], |
320 | 68 | u[9], u[10], u[11]); |
321 | 68 | break; |
322 | 69 | case 0x83: |
323 | | // Interference Detection Status |
324 | 69 | u[0] = getub(buf, 2); |
325 | 69 | u[1] = getub(buf, 3); |
326 | 69 | GPSD_LOG(LOG_PROG, &session->context->errout, |
327 | 69 | "Skytraq 0x64/83: enable %u status %u\n", |
328 | 69 | u[0], u[1]); |
329 | 69 | break; |
330 | 67 | case 0x85: |
331 | | // GPS PARAMETER SEARCH ENGINE NUMBER |
332 | 67 | u[0] = getub(buf, 2); |
333 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
334 | 67 | "Skytraq 0x64/85: search engine number %u\n", u[0]); |
335 | 67 | break; |
336 | 70 | case 0x88: |
337 | | // Position/Fix navigation mask |
338 | 70 | u[0] = getub(buf, 2); |
339 | 70 | u[1] = getub(buf, 3); |
340 | 70 | GPSD_LOG(LOG_PROG, &session->context->errout, |
341 | 70 | "Skytraq 0x64/88: 1st %u subsequent %u\n", |
342 | 70 | u[0], u[1]); |
343 | 70 | break; |
344 | 69 | case 0x8a: |
345 | | // GPS UTC Reference time |
346 | 69 | if (7 > len) { |
347 | 2 | GPSD_LOG(LOG_WARN, &session->context->errout, |
348 | 2 | "Skytraq 0x64/8a: bad len %zu\n", len); |
349 | 2 | return 0; |
350 | 2 | } |
351 | 67 | u[0] = getub(buf, 2); |
352 | 67 | u[1] = getbeu16(buf, 3); |
353 | 67 | u[2] = getub(buf, 5); |
354 | 67 | u[3] = getub(buf, 6); |
355 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
356 | 67 | "Skytraq 0x64/8a: enable %u year %u month %u day %u\n", |
357 | 67 | u[0], u[1], u[2], u[3]); |
358 | 67 | break; |
359 | 67 | case 0x8b: |
360 | | // GNSS Nav mode |
361 | 67 | u[0] = getub(buf, 2); |
362 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
363 | 67 | "Skytraq 0x64/8b: mode %u\n", u[0]); |
364 | 67 | break; |
365 | 69 | case 0x8c: |
366 | | // GNSS Constellation type for nav solution |
367 | 69 | u[0] = getbeu16(buf, 2); |
368 | 69 | GPSD_LOG(LOG_PROG, &session->context->errout, |
369 | 69 | "Skytraq 0x64/8c: Nav Type x%02x\n", u[0]); |
370 | 69 | break; |
371 | 72 | case 0x8e: |
372 | | // GPS time |
373 | 72 | u[0] = getbeu32(buf, 2); // TOW ms |
374 | 72 | u[1] = getbeu32(buf, 6); // TOW ns |
375 | 72 | u[2] = getbeu16(buf, 10); // GPS week |
376 | 72 | s[0] = getsb(buf, 12); // default leap s |
377 | 72 | s[1] = getsb(buf, 13); // current leap s |
378 | 72 | u[3] = getub(buf, 14); // valid |
379 | | // FIXME: save GPS week and leap s |
380 | 72 | GPSD_LOG(LOG_PROG, &session->context->errout, |
381 | 72 | "Skytraq 0x64/8a: TOW %u %u week %u leap %d %d valid x%x\n", |
382 | 72 | u[0], u[1], u[2], s[0], s[1], u[3]); |
383 | 72 | break; |
384 | 72 | case 0x92: |
385 | | // GLONASS Time corrections |
386 | 72 | s[0] = getbes32(buf, 2); // tau c |
387 | 72 | s[1] = getbes32(buf, 6); // tau gps |
388 | 72 | GPSD_LOG(LOG_PROG, &session->context->errout, |
389 | 72 | "Skytraq 0x64/92: tau c %d tau GPS %d\n", |
390 | 72 | s[0], s[1]); |
391 | 72 | break; |
392 | 67 | case 0xfe: |
393 | | // Version extension string |
394 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
395 | 67 | "Skytraq 0x64/fe: >%.32s<\n", &buf[2]); |
396 | 67 | break; |
397 | 122 | default: |
398 | 122 | GPSD_LOG(LOG_PROG, &session->context->errout, |
399 | 984 | "Skytraq 0x64: SID x%02x len %zu\n", sid, len); |
400 | 984 | } |
401 | 914 | return 0; |
402 | 984 | } |
403 | | |
404 | | /* |
405 | | * decode MID 0x65 -- super packet |
406 | | * |
407 | | * Present in Phoenix |
408 | | */ |
409 | | static gps_mask_t sky_msg_65(struct gps_device_t *session, |
410 | | const unsigned char *buf, const size_t len) |
411 | 339 | { |
412 | 339 | unsigned sid; |
413 | 339 | unsigned u[13]; |
414 | | |
415 | 339 | if (3 > len) { |
416 | 101 | GPSD_LOG(LOG_WARN, &session->context->errout, |
417 | 101 | "Skytraq 0x65: bad len %zu\n", len); |
418 | 101 | return 0; |
419 | 101 | } |
420 | | |
421 | 238 | sid = getub(buf, 1); |
422 | 238 | switch (sid) { |
423 | 68 | case 0x80: |
424 | | // 1PPS Pulse width |
425 | 68 | u[0] = getbeu32(buf, 2); // pulse width miicro seconds |
426 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
427 | 68 | "Skytraq 0x65/80: width %u\n", u[0]); |
428 | 68 | break; |
429 | 68 | case 0x81: |
430 | | // PPS2 frequency |
431 | 68 | u[0] = getbeu32(buf, 2); // freq of PPS2 Hz |
432 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
433 | 68 | "Skytraq 0x65/81: PPS2 Hz %u\n", u[0]); |
434 | 68 | break; |
435 | 102 | default: |
436 | 102 | GPSD_LOG(LOG_PROG, &session->context->errout, |
437 | 238 | "Skytraq 0x65: SID x%02x len %zu\n", sid, len); |
438 | 238 | } |
439 | 238 | return 0; |
440 | 238 | } |
441 | | |
442 | | /* |
443 | | * decode MID 0x6A -- super packet |
444 | | * |
445 | | * Present in Phoenix |
446 | | */ |
447 | | static gps_mask_t sky_msg_6A(struct gps_device_t *session, |
448 | | const unsigned char *buf, const size_t len) |
449 | 300 | { |
450 | 300 | unsigned sid; |
451 | 300 | unsigned u[13]; |
452 | 300 | double d[5]; |
453 | | |
454 | 300 | if (3 > len) { |
455 | 158 | GPSD_LOG(LOG_WARN, &session->context->errout, |
456 | 158 | "Skytraq 0x6A: bad len %zu\n", len); |
457 | 158 | return 0; |
458 | 158 | } |
459 | | |
460 | 142 | sid = getub(buf, 1); |
461 | 142 | switch (sid) { |
462 | 1 | case 0x83: |
463 | | // RTK mode and operational functioN |
464 | 1 | u[0] = getub(buf, 2); // RTK mode |
465 | 1 | u[1] = getub(buf, 3); // RTK function |
466 | 1 | u[2] = getbeu32(buf, 4); // saved survey length |
467 | 1 | u[3] = getbeu32(buf, 8); // standard deviation |
468 | 1 | d[0] = getled64((const char *)buf, 12); // latitude |
469 | 1 | d[1] = getled64((const char *)buf, 20); // longitude |
470 | 1 | d[3] = getlef32((const char *)buf, 28); // altitude (HAE or MSL?) |
471 | 1 | u[4] = getub(buf, 32); // runtime function |
472 | 1 | u[5] = getbeu32(buf, 33); // run-time survey length |
473 | 1 | d[4] = getlef32((const char *)buf, 37); // baseline length constant |
474 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
475 | 1 | "Skytraq 0x6A/83: mode %u func %u len %u sdev %u lat %.8f " |
476 | 1 | "lon %.8f alt %.4f func %u len %u len %.4f\n", |
477 | 1 | u[0], u[1], u[2], u[3], d[0], d[1], d[3], u[4], u[5], d[4]); |
478 | 1 | break; |
479 | 68 | case 0x85: |
480 | | // RTK slave base serial port baud ratE |
481 | 68 | u[0] = getub(buf, 2); // rate code |
482 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
483 | 68 | "Skytraq 0x6A/85: rate %u\n", u[0]); |
484 | 68 | break; |
485 | 1 | case 0x88: |
486 | | // RTK kinematic base serial port baud ratE |
487 | 1 | u[0] = getub(buf, 2); // rate code |
488 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
489 | 1 | "Skytraq 0x6A/88: rate %u\n", u[0]); |
490 | 1 | break; |
491 | 72 | default: |
492 | 72 | GPSD_LOG(LOG_PROG, &session->context->errout, |
493 | 142 | "Skytraq 0x6A: SID x%02x len %zu\n", sid, len); |
494 | 142 | } |
495 | 142 | return 0; |
496 | 142 | } |
497 | | |
498 | | /* |
499 | | * decode MID 0x7A -- super packet |
500 | | * |
501 | | * Present in Phoenix |
502 | | */ |
503 | | static gps_mask_t sky_msg_7A(struct gps_device_t *session, |
504 | | const unsigned char *buf, const size_t len) |
505 | 327 | { |
506 | 327 | unsigned sid, ssid; |
507 | 327 | unsigned u[16]; |
508 | 327 | double d[2]; |
509 | 327 | int i; |
510 | | |
511 | 327 | if (3 > len) { |
512 | 219 | GPSD_LOG(LOG_WARN, &session->context->errout, |
513 | 219 | "Skytraq 0x7A: bad len %zu\n", len); |
514 | 219 | return 0; |
515 | 219 | } |
516 | | |
517 | 108 | sid = getub(buf, 1); |
518 | 108 | ssid = getub(buf, 2); |
519 | 108 | switch ((sid << 8) | ssid) { |
520 | 2 | case 0x0e80: |
521 | | // Moving base software version |
522 | 2 | if (16 > len) { |
523 | 1 | GPSD_LOG(LOG_WARN, &session->context->errout, |
524 | 1 | "Skytraq 0x7A/0E/80: bad len %zu\n", len); |
525 | 1 | return 0; |
526 | 1 | } |
527 | 14 | for (i = 0; i < 13; i++) { |
528 | 13 | u[i] = getub(buf, i + 3); |
529 | 13 | } |
530 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
531 | 1 | "Skytraq 0x7A/0E/80: type %u " |
532 | 1 | "kver %u.%u.%u over %u.%u.%u rev %02u.%02u.%02u\n", |
533 | 1 | u[0], u[2], u[3], u[4], u[6], u[7], u[8], u[10], |
534 | 1 | u[11], u[12]); |
535 | 1 | break; |
536 | 1 | case 0x0e81: |
537 | | // Moving base software CRC |
538 | 1 | u[0] = getub(buf, 3); |
539 | 1 | u[1] = getbeu16(buf, 4); |
540 | | |
541 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
542 | 1 | "Skytraq 0x7A/0E/801: type %u crc %u\n", u[0], u[1]); |
543 | 1 | break; |
544 | 1 | case 0x0e82: |
545 | | // Moving base pos update rate |
546 | 1 | u[0] = getub(buf, 3); |
547 | | |
548 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
549 | 1 | "Skytraq 0x7A/0E/802: rate %u\n", u[0]); |
550 | 1 | break; |
551 | 1 | case 0x0e83: |
552 | | // Moving base heading and pitch offsets |
553 | 1 | d[0] = getbeu32(buf, 3); // heading |
554 | 1 | d[1] = getbeu32(buf, 7); // pitch |
555 | | |
556 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
557 | 1 | "Skytraq 0x7A/0E/803: heading %f pitch %f\n", d[0], d[1]); |
558 | 1 | break; |
559 | 103 | default: |
560 | 103 | GPSD_LOG(LOG_PROG, &session->context->errout, |
561 | 108 | "Skytraq 0x7A: SID x%02x/%02x len %zu\n", sid, ssid, len); |
562 | 108 | } |
563 | 107 | return 0; |
564 | 108 | } |
565 | | |
566 | | /* |
567 | | * decode MID 0x80, Software Version |
568 | | * |
569 | | * 10 bytes |
570 | | * |
571 | | * Present in: Venus 6 |
572 | | * Venus 8 |
573 | | * Phoenix |
574 | | */ |
575 | | static gps_mask_t sky_msg_80(struct gps_device_t *session, |
576 | | const unsigned char *buf, const size_t len) |
577 | 171 | { |
578 | 171 | unsigned kver_x; // kernel version |
579 | 171 | unsigned kver_y; // kernel version |
580 | 171 | unsigned kver_z; // kernel version |
581 | 171 | unsigned over_x; // ODM version |
582 | 171 | unsigned over_y; // ODM version |
583 | 171 | unsigned over_z; // ODM version |
584 | 171 | unsigned rev_yy; // revision |
585 | 171 | unsigned rev_mm; // revision |
586 | 171 | unsigned rev_dd; // revision |
587 | | |
588 | 171 | if (14 != len) { |
589 | 101 | return 0; |
590 | 101 | } |
591 | | |
592 | 70 | kver_x = getbeu16(buf, 2); |
593 | 70 | kver_y = getub(buf, 4); |
594 | 70 | kver_z = getub(buf, 5); |
595 | 70 | over_x = getbeu16(buf, 6); |
596 | 70 | over_y = getub(buf, 8); |
597 | 70 | over_z = getub(buf, 9); |
598 | 70 | rev_yy = getbeu16(buf, 10); |
599 | 70 | rev_mm = getub(buf, 12); |
600 | 70 | rev_dd = getub(buf, 13); |
601 | | |
602 | 70 | (void)snprintf(session->subtype, sizeof(session->subtype) - 1, |
603 | 70 | "kver %u.%u.%u over %u.%u.%u rev %02u.%02u.%02u", |
604 | 70 | kver_x, kver_y, kver_z, |
605 | 70 | over_x, over_y, over_z, |
606 | 70 | rev_yy, rev_mm, rev_dd); |
607 | | |
608 | 70 | GPSD_LOG(LOG_PROG, &session->context->errout, |
609 | 70 | "Skytraq 0x80: %s\n", |
610 | 70 | session->subtype); |
611 | 70 | return 0; |
612 | 171 | } |
613 | | |
614 | | /* |
615 | | * decode MID 0x81 - Software CRC |
616 | | * |
617 | | * Present in Phoenix |
618 | | */ |
619 | | static gps_mask_t sky_msg_81(struct gps_device_t *session, |
620 | | const unsigned char *buf, const size_t len) |
621 | 68 | { |
622 | 68 | unsigned type, crc; |
623 | | |
624 | 68 | if (4 != len) { |
625 | 67 | GPSD_LOG(LOG_WARN, &session->context->errout, |
626 | 67 | "Skytraq 0x81: bad len %zu\n", len); |
627 | 67 | return 0; |
628 | 67 | } |
629 | | |
630 | 1 | type = getub(buf, 1); |
631 | 1 | crc = getbeu16(buf, 2); |
632 | | |
633 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
634 | 1 | "Skytraq 0x81: type %u crc %u\n", type, crc); |
635 | 1 | return 0; |
636 | 68 | } |
637 | | |
638 | | /* |
639 | | * decode MID 0x86 - Position Update Rate |
640 | | * |
641 | | * Present in Phoenix |
642 | | */ |
643 | | static gps_mask_t sky_msg_86(struct gps_device_t *session, |
644 | | const unsigned char *buf, const size_t len) |
645 | 168 | { |
646 | 168 | unsigned rate; |
647 | | |
648 | 168 | if (2 != len) { |
649 | 70 | GPSD_LOG(LOG_WARN, &session->context->errout, |
650 | 70 | "Skytraq 0x86: bad len %zu\n", len); |
651 | 70 | return 0; |
652 | 70 | } |
653 | | |
654 | 98 | rate = getub(buf, 1); |
655 | | |
656 | 98 | GPSD_LOG(LOG_PROG, &session->context->errout, |
657 | 98 | "Skytraq 0x86: rate %u\n", rate); |
658 | 98 | return 0; |
659 | 168 | } |
660 | | |
661 | | /* |
662 | | * decode MID 0x89 - Binary measurement data output status |
663 | | * |
664 | | * Present in Phoenix |
665 | | */ |
666 | | static gps_mask_t sky_msg_89(struct gps_device_t *session, |
667 | | const unsigned char *buf, const size_t len) |
668 | 120 | { |
669 | 120 | unsigned i; |
670 | 120 | uint8_t u[7]; |
671 | | |
672 | 120 | if (8 != len) { |
673 | 119 | GPSD_LOG(LOG_WARN, &session->context->errout, |
674 | 119 | "Skytraq 0x89: bad len %zu\n", len); |
675 | 119 | return 0; |
676 | 119 | } |
677 | | |
678 | 8 | for (i = 0; i < 7; i++) { |
679 | 7 | u[i] = getub(buf, i + 1); |
680 | 7 | } |
681 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
682 | 1 | "Skytraq 0x89: rate %u Meas %u raw %u CH_status %u " |
683 | 1 | "RCV_statas %u subf %u eraw %u\n", |
684 | 1 | u[0], u[1], u[2], u[3], u[4], u[5], u[6]); |
685 | | |
686 | 1 | return 0; |
687 | 120 | } |
688 | | |
689 | | /* |
690 | | * decode MID 0x8A - Binary rtcm data output status |
691 | | * |
692 | | * Present in Phoenix |
693 | | */ |
694 | | static gps_mask_t sky_msg_8A(struct gps_device_t *session, |
695 | | const unsigned char *buf, const size_t len) |
696 | 489 | { |
697 | 489 | unsigned i; |
698 | 489 | uint8_t u[15]; |
699 | | |
700 | 489 | if (16 != len) { |
701 | 488 | GPSD_LOG(LOG_WARN, &session->context->errout, |
702 | 488 | "Skytraq 0x8A: bad len %zu\n", len); |
703 | 488 | return 0; |
704 | 488 | } |
705 | | |
706 | 16 | for (i = 0; i < 15; i++) { |
707 | 15 | u[i] = getub(buf, i + 1); |
708 | 15 | } |
709 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
710 | 1 | "Skytraq 0x8A: enable %u MSM %u 1005 %u 107x %u 108x %u " |
711 | 1 | "109x %u 110x %u 111x %u 112x %u 1019 %u 1020 %u " |
712 | 1 | "1042 %u 1046 %u type %u version %u\n", |
713 | 1 | u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], |
714 | 1 | u[8], u[9], u[10], u[11], u[12], u[13], u[14]); |
715 | | |
716 | 1 | return 0; |
717 | 489 | } |
718 | | |
719 | | /* |
720 | | * decode MID 0x8B - Base position |
721 | | * |
722 | | * Present in Phoenix |
723 | | */ |
724 | | static gps_mask_t sky_msg_8B(struct gps_device_t *session, |
725 | | const unsigned char *buf, const size_t len) |
726 | 172 | { |
727 | 172 | uint8_t u[5]; |
728 | 172 | double d[3]; |
729 | | |
730 | 172 | if (35 != len) { |
731 | 104 | GPSD_LOG(LOG_WARN, &session->context->errout, |
732 | 104 | "Skytraq 0x8B: bad len %zu\n", len); |
733 | 104 | return 0; |
734 | 104 | } |
735 | | |
736 | 68 | u[0] = getub(buf, 1); |
737 | 68 | u[1] = getbeu32(buf, 2); |
738 | 68 | u[2] = getbeu32(buf, 6); |
739 | 68 | d[0] = getbed64((const char *)buf, 10); |
740 | 68 | d[1] = getbed64((const char *)buf, 18); |
741 | 68 | d[2] = getbef32((const char *)buf, 26); |
742 | 68 | u[3] = getub(buf, 30); |
743 | 68 | u[4] = getbeu32(buf, 31); |
744 | | |
745 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
746 | 68 | "Skytraq 0x8B: saved mode %u saved length %u stddev %u " |
747 | 68 | "lat %.9f lon %.9f HAE %0.4f run mode %u survey len %u\n", |
748 | 68 | u[0], u[1], u[2], d[0], d[1], d[2], u[3], u[4]); |
749 | | |
750 | 68 | return 0; |
751 | 172 | } |
752 | | |
753 | | /* |
754 | | * decode MID 0x93 - NMEA Talker ID |
755 | | * |
756 | | * Present in Phoenix |
757 | | */ |
758 | | static gps_mask_t sky_msg_93(struct gps_device_t *session, |
759 | | const unsigned char *buf, const size_t len) |
760 | 154 | { |
761 | 154 | unsigned mode; |
762 | | |
763 | 154 | if (2 != len) { |
764 | 75 | GPSD_LOG(LOG_WARN, &session->context->errout, |
765 | 75 | "Skytraq 0x93: bad len %zu\n", len); |
766 | 75 | return 0; |
767 | 75 | } |
768 | | |
769 | 79 | mode = getub(buf, 1); |
770 | | |
771 | 79 | GPSD_LOG(LOG_PROG, &session->context->errout, |
772 | 79 | "Skytraq 0x93: mode %u\n", mode); |
773 | 79 | return 0; |
774 | 154 | } |
775 | | |
776 | | /* |
777 | | * Binary Navigation Data Message (0xA8) |
778 | | * Returns 59 bytes; |
779 | | * Fix Mode, SV, Week, TOW, Latitude, Longitude, ellipsoid altitude, |
780 | | * mean sea level altitude, gdop, pdop, hdop, vdop, tdop, |
781 | | * ecef.{x,y,z}, ecef_v.{x,y,z} |
782 | | * |
783 | | * The following message (0xA8) is emitted by the modules supporting |
784 | | * the Binary Messages Raw Measurements Data Extension in AN0028 |
785 | | * (https://www.skytraq.com.tw/homesite/AN0028.pdf) |
786 | | * Original implementation by Kai Harrekilde-Petersen |
787 | | * and adapted by Thatcher Chamberlin (j.thatcher.c@gmail.com) |
788 | | */ |
789 | | static gps_mask_t sky_msg_A8(struct gps_device_t *session, |
790 | | const unsigned char *buf, const size_t len) |
791 | 90 | { |
792 | 90 | unsigned char navmode; // Navigation fix mode (0: No fix, 1: 2D, 2: 3D, 3: 3D+DGNSS |
793 | 90 | unsigned short week; // GNSS week number |
794 | 90 | double ftow; // Time of week |
795 | 90 | timespec_t ts_tow; |
796 | 90 | char ts_buf[TIMESPEC_LEN]; |
797 | | |
798 | 90 | int *mode = &session->newdata.mode; |
799 | 90 | int *status = &session->newdata.status; |
800 | 90 | gps_mask_t mask = 0; |
801 | | |
802 | 90 | if (59 != len) { |
803 | 87 | GPSD_LOG(LOG_INF, &session->context->errout, "Skytraq: " |
804 | 87 | "Navigation Data Message has incorrect length %zu\n", len); |
805 | 87 | return 0; |
806 | 87 | } |
807 | | |
808 | 3 | navmode = getub(buf, 1); |
809 | 3 | switch (navmode) { |
810 | 1 | case 1: // 2D fix |
811 | 1 | *mode = MODE_2D; |
812 | 1 | *status = STATUS_GPS; |
813 | 1 | break; |
814 | 1 | case 2: // 3D fix |
815 | 1 | *mode = MODE_3D; |
816 | 1 | *status = STATUS_GPS; |
817 | 1 | break; |
818 | 0 | case 3: // 3D DGPS fix |
819 | 0 | *mode = MODE_3D; |
820 | 0 | *status = STATUS_DGPS; |
821 | 0 | break; |
822 | | |
823 | 1 | default: // Includes SKY_MODE_NONE |
824 | 1 | *mode = MODE_NO_FIX; |
825 | 1 | *status = STATUS_UNK; |
826 | 1 | break; |
827 | 3 | } |
828 | 3 | mask |= MODE_SET | STATUS_SET; |
829 | | |
830 | 3 | session->gpsdata.satellites_used = getub(buf, 2); |
831 | | |
832 | 3 | mask |= ONLINE_SET; |
833 | 3 | week = getbeu16(buf, 3); |
834 | 3 | ftow = getbeu32(buf, 5) / 100.0; |
835 | 3 | DTOTS(&ts_tow, (int)ftow); |
836 | | |
837 | 3 | session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow); |
838 | 3 | mask |= TIME_SET; |
839 | | |
840 | 3 | if (MODE_2D == *mode || MODE_3D == *mode) { |
841 | 2 | session->newdata.latitude = getbes32(buf, 9) / 1e7; |
842 | 2 | session->newdata.longitude = getbes32(buf, 13) / 1e7; |
843 | 2 | mask |= LATLON_SET | NTPTIME_IS; |
844 | | |
845 | 2 | if (MODE_3D == *mode) { |
846 | 1 | session->newdata.altHAE = getbes32(buf, 17) / 100.0; |
847 | 1 | session->newdata.altMSL = getbes32(buf, 21) / 100.0; |
848 | | |
849 | 1 | session->newdata.ecef.x = getbes32(buf, 35) / 100.0; |
850 | 1 | session->newdata.ecef.y = getbes32(buf, 39) / 100.0; |
851 | 1 | session->newdata.ecef.z = getbes32(buf, 43) / 100.0; |
852 | 1 | session->newdata.ecef.vx = getbes32(buf, 47) / 100.0; |
853 | 1 | session->newdata.ecef.vy = getbes32(buf, 51) / 100.0; |
854 | 1 | session->newdata.ecef.vz = getbes32(buf, 55) / 100.0; |
855 | 1 | mask |= ECEF_SET | VECEF_SET | ALTITUDE_SET; |
856 | 1 | } |
857 | 2 | } |
858 | | |
859 | 3 | session->gpsdata.dop.gdop = getbeu16(buf, 25) / 100.0; |
860 | 3 | session->gpsdata.dop.pdop = getbeu16(buf, 27) / 100.0; |
861 | 3 | session->gpsdata.dop.hdop = getbeu16(buf, 29) / 100.0; |
862 | 3 | session->gpsdata.dop.vdop = getbeu16(buf, 31) / 100.0; |
863 | 3 | session->gpsdata.dop.tdop = getbeu16(buf, 33) / 100.0; |
864 | 3 | mask |= DOP_SET | CLEAR_IS | REPORT_IS; |
865 | 3 | GPSD_LOG(LOG_DATA, &session->context->errout, |
866 | 3 | "Skytraq: NAVDATA time=%s, lat=%.7f lon=%.7f altHAE=%.2f altMSL=%.2f mode=%d status=%d " |
867 | 3 | "gdop: %.2f, hdop: %.2f, pdop: %.2f, tdop: %.2f, vdop: %.2f\n", |
868 | 3 | timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)), |
869 | 3 | session->newdata.latitude, |
870 | 3 | session->newdata.longitude, |
871 | 3 | session->newdata.altHAE, |
872 | 3 | session->newdata.altMSL, |
873 | 3 | session->newdata.mode, |
874 | 3 | session->newdata.status, |
875 | 3 | session->gpsdata.dop.gdop, |
876 | 3 | session->gpsdata.dop.hdop, |
877 | 3 | session->gpsdata.dop.pdop, |
878 | 3 | session->gpsdata.dop.tdop, |
879 | 3 | session->gpsdata.dop.vdop); |
880 | 3 | return mask; |
881 | 3 | } |
882 | | |
883 | | /* |
884 | | * decode MID 0xAE - GNSS Datum |
885 | | * |
886 | | * Present in Phoenix |
887 | | */ |
888 | | static gps_mask_t sky_msg_AE(struct gps_device_t *session, |
889 | | const unsigned char *buf, const size_t len) |
890 | 1.02k | { |
891 | 1.02k | unsigned datum; |
892 | | |
893 | 1.02k | if (3 != len) { |
894 | 867 | GPSD_LOG(LOG_WARN, &session->context->errout, |
895 | 867 | "Skytraq 0xAE: bad len %zu\n", len); |
896 | 867 | return 0; |
897 | 867 | } |
898 | | |
899 | 156 | datum = getbeu16(buf, 1); |
900 | | |
901 | 156 | GPSD_LOG(LOG_PROG, &session->context->errout, |
902 | 156 | "Skytraq 0xAE: datum %u\n", datum); |
903 | 156 | return 0; |
904 | 1.02k | } |
905 | | |
906 | | /* |
907 | | * decode MID 0xaf - DOP mask |
908 | | * |
909 | | * Present in Phoenix |
910 | | */ |
911 | | static gps_mask_t sky_msg_AF(struct gps_device_t *session, |
912 | | const unsigned char *buf, const size_t len) |
913 | 139 | { |
914 | 139 | unsigned mode, pdop, hdop, gdop; |
915 | | |
916 | 139 | if (8 != len) { |
917 | 138 | GPSD_LOG(LOG_WARN, &session->context->errout, |
918 | 138 | "Skytraq 0xAF: bad len %zu\n", len); |
919 | 138 | return 0; |
920 | 138 | } |
921 | | |
922 | 1 | mode = getub(buf, 1); |
923 | 1 | pdop = getbeu16(buf, 2); |
924 | 1 | hdop = getbeu16(buf, 4); |
925 | 1 | gdop = getbeu16(buf, 6); |
926 | | |
927 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
928 | 1 | "Skytraq 0xAF: Masks: mode %u pdop %u hdop %u gdop %u\n", |
929 | 1 | mode, pdop, hdop, gdop); |
930 | 1 | return 0; |
931 | 139 | } |
932 | | |
933 | | /* |
934 | | * decode MID 0xb0 Elevation and DOP mask |
935 | | * |
936 | | * Present in Phoenix |
937 | | */ |
938 | | static gps_mask_t sky_msg_B0(struct gps_device_t *session, |
939 | | const unsigned char *buf, const size_t len) |
940 | 93 | { |
941 | 93 | unsigned select, elevation, cnr; |
942 | | |
943 | 93 | if (4 != len) { |
944 | 92 | GPSD_LOG(LOG_WARN, &session->context->errout, |
945 | 92 | "Skytraq 0xB0: bad len %zu\n", len); |
946 | 92 | return 0; |
947 | 92 | } |
948 | | |
949 | 1 | select = getub(buf, 1); |
950 | 1 | elevation = getub(buf, 2); |
951 | 1 | cnr = getub(buf, 3); |
952 | | |
953 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
954 | 1 | "Skytraq 0xB0: select %u el %u cnr %u\n", |
955 | 1 | select, elevation, cnr); |
956 | 1 | return 0; |
957 | 93 | } |
958 | | |
959 | | /* |
960 | | * decode MID 0xb4 - Position Pinning Status |
961 | | * |
962 | | * Present in Phoenix |
963 | | */ |
964 | | static gps_mask_t sky_msg_B4(struct gps_device_t *session, |
965 | | const unsigned char *buf, const size_t len) |
966 | 79 | { |
967 | 79 | unsigned status, pspeed, pcnt, uspeed, ucnt, udist; |
968 | | |
969 | 79 | if (12 != len) { |
970 | 78 | GPSD_LOG(LOG_WARN, &session->context->errout, |
971 | 78 | "Skytraq 0xB4: bad len %zu\n", len); |
972 | 78 | return 0; |
973 | 78 | } |
974 | | |
975 | 1 | status = getub(buf, 1); |
976 | 1 | pspeed = getbeu16(buf, 2); |
977 | 1 | pcnt = getbeu16(buf, 4); |
978 | 1 | uspeed = getbeu16(buf, 6); |
979 | 1 | ucnt = getbeu16(buf, 8); |
980 | 1 | udist = getbeu16(buf, 10); |
981 | | |
982 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
983 | 1 | "Skytraq 0xB4: status %u pspeed %u pcnt %u uspeed %u " |
984 | 1 | "ucnt %u udist %u\n", |
985 | 1 | status, pspeed, pcnt, uspeed, ucnt, udist); |
986 | 1 | return 0; |
987 | 79 | } |
988 | | |
989 | | /* |
990 | | * decode MID 0xB9 - Power Mode Status |
991 | | * |
992 | | * Present in Phoenix |
993 | | */ |
994 | | static gps_mask_t sky_msg_B9(struct gps_device_t *session, |
995 | | const unsigned char *buf, const size_t len) |
996 | 321 | { |
997 | 321 | unsigned mode; |
998 | | |
999 | 321 | if (2 != len) { |
1000 | 254 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1001 | 254 | "Skytraq 0xB9: bad len %zu\n", len); |
1002 | 254 | return 0; |
1003 | 254 | } |
1004 | | |
1005 | 67 | mode = getub(buf, 1); |
1006 | | |
1007 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1008 | 67 | "Skytraq 0xB9: mode %u\n", mode); |
1009 | 67 | return 0; |
1010 | 321 | } |
1011 | | |
1012 | | /* |
1013 | | * decode MID 0xBB - 1PPS Cable Delay |
1014 | | * |
1015 | | * Present in Phoenix |
1016 | | */ |
1017 | | static gps_mask_t sky_msg_BB(struct gps_device_t *session, |
1018 | | const unsigned char *buf, const size_t len) |
1019 | 69 | { |
1020 | 69 | int delay; |
1021 | | |
1022 | 69 | if (5 != len) { |
1023 | 68 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1024 | 68 | "Skytraq 0xBB: bad len %zu\n", len); |
1025 | 68 | return 0; |
1026 | 68 | } |
1027 | | |
1028 | 1 | delay = getbeu32(buf, 1); |
1029 | | |
1030 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1031 | 1 | "Skytraq 0xBB: delay %d\n", delay); |
1032 | 1 | return 0; |
1033 | 69 | } |
1034 | | |
1035 | | /* |
1036 | | * decode MID 0xDC, Measurement Time |
1037 | | * |
1038 | | * 10 bytes |
1039 | | */ |
1040 | | static gps_mask_t sky_msg_DC(struct gps_device_t *session, |
1041 | | const unsigned char *buf, const size_t len) |
1042 | 271 | { |
1043 | 271 | unsigned iod; // Issue of data 0 - 255 |
1044 | 271 | unsigned wn; // week number 0 - 65535 |
1045 | 271 | unsigned tow; // receiver tow 0 - 604799999 in mS |
1046 | 271 | unsigned mp; // measurement period 1 - 1000 ms |
1047 | 271 | char ts_buf[TIMESPEC_LEN]; |
1048 | 271 | timespec_t ts_tow; |
1049 | | |
1050 | 271 | if (10 != len) { |
1051 | 194 | return 0; |
1052 | 194 | } |
1053 | | |
1054 | 77 | iod = (unsigned)getub(buf, 1); |
1055 | 77 | wn = getbeu16(buf, 2); |
1056 | 77 | tow = getbeu32(buf, 4); |
1057 | 77 | mp = getbeu16(buf, 8); |
1058 | 77 | MSTOTS(&ts_tow, tow); |
1059 | | |
1060 | | // should this be newdata.skyview_time? |
1061 | 77 | session->gpsdata.skyview_time = gpsd_gpstime_resolv(session, wn, ts_tow); |
1062 | | |
1063 | 77 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1064 | 77 | "Skytraq 0xDC: iod %u wn %u tow %u mp %u t%s\n", |
1065 | 77 | iod, wn, tow, mp, |
1066 | 77 | timespec_str(&session->gpsdata.skyview_time, ts_buf, |
1067 | 77 | sizeof(ts_buf))); |
1068 | 77 | return 0; |
1069 | 271 | } |
1070 | | |
1071 | | /* |
1072 | | * decode MID 0xDD, Raw Measurements |
1073 | | * |
1074 | | */ |
1075 | | static gps_mask_t sky_msg_DD(struct gps_device_t *session, |
1076 | | const unsigned char *buf, const size_t len) |
1077 | 895 | { |
1078 | 895 | unsigned i; // generic loop variable |
1079 | | |
1080 | | // buf[0] os the message ID |
1081 | | // Issue of data 0 - 255 |
1082 | 895 | unsigned iod = (unsigned)getub(buf, 1); |
1083 | | // number of measurements |
1084 | 895 | unsigned nmeas = (unsigned)getub(buf, 2); |
1085 | | |
1086 | 895 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1087 | 895 | "Skytraq 0xDD: iod %u, nmeas %u len %zd\n", |
1088 | 895 | iod, nmeas, len); |
1089 | | |
1090 | 895 | if (len < (3 + (nmeas * 23))) { |
1091 | 109 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
1092 | 109 | "Skytraq 0xDD: bad len %zd, s/b %d\n", |
1093 | 109 | len, 3 + (nmeas & 23)); |
1094 | 109 | return 0; |
1095 | 109 | } |
1096 | | |
1097 | | // check IOD? |
1098 | 786 | session->gpsdata.raw.mtime = session->gpsdata.skyview_time; |
1099 | | |
1100 | | /* zero the measurement data |
1101 | | * so we can tell which meas never got set */ |
1102 | 786 | memset(session->gpsdata.raw.meas, 0, sizeof(session->gpsdata.raw.meas)); |
1103 | | |
1104 | 4.80k | for (i = 0; i < nmeas; i++) { |
1105 | 4.01k | const char *obs_code; |
1106 | 4.01k | int off = 3 + (23 * i); |
1107 | | |
1108 | 4.01k | uint8_t PRN = getub(buf, off + 0); |
1109 | | // carrier-to-noise density ratio dB-Hz |
1110 | 4.01k | uint8_t cno = getub(buf, off + 1); |
1111 | | // pseudorange in meters |
1112 | 4.01k | double prMes = getbed64((const char *)buf, off + 2); |
1113 | | // carrier phase in cycles |
1114 | 4.01k | double cpMes = getbed64((const char *)buf, off + 10); |
1115 | | // doppler in Hz, positive towards sat |
1116 | 4.01k | double doMes = getbef32((const char *)buf, off + 18); |
1117 | | |
1118 | | /* tracking stat |
1119 | | * bit 0 - prMes valid |
1120 | | * bit 1 - doppler valid |
1121 | | * bit 2 - cpMes valid |
1122 | | * bit 3 - cp slip |
1123 | | * bit 4 - Coherent integration time? |
1124 | | */ |
1125 | 4.01k | uint8_t trkStat = getub(buf, off + 22); |
1126 | 4.01k | uint8_t gnssId = 0; |
1127 | | // svId should always be from 0 to 99, except SBAS. |
1128 | 4.01k | uint8_t svId = 0; |
1129 | 4.01k | PRN2_gnssId_svId(PRN, &gnssId, &svId); |
1130 | | |
1131 | 4.01k | session->gpsdata.raw.meas[i].gnssid = gnssId; |
1132 | 4.01k | switch (gnssId) { |
1133 | 2.57k | case 0: // GPS |
1134 | 2.57k | FALLTHROUGH |
1135 | 2.57k | case 5: // QZSS |
1136 | 2.57k | FALLTHROUGH |
1137 | 2.71k | case 20: // IRNSS, just guessing here |
1138 | 2.71k | obs_code = "L1C"; // u-blox calls this L1C/A ? |
1139 | 2.71k | break; |
1140 | 372 | case 1: // SBAS |
1141 | 372 | if (100 < svId) { |
1142 | | // Should be always true, but pacify Coverity 498045 |
1143 | 372 | svId -= 100; // adjust for RINEX 3 svid |
1144 | 372 | } |
1145 | 372 | obs_code = "L1C"; // u-blox calls this L1C/A |
1146 | 372 | break; |
1147 | 0 | case 2: // GALILEO |
1148 | 0 | obs_code = "L1B"; // u-blox calls this E1OS |
1149 | 0 | break; |
1150 | 231 | case 3: // BeiDou |
1151 | 231 | obs_code = "L2I"; // u-blox calls this B1I |
1152 | 231 | break; |
1153 | 0 | default: // huh? |
1154 | 0 | FALLTHROUGH |
1155 | 0 | case 4: // IMES. really? |
1156 | 0 | obs_code = ""; // u-blox calls this L1 |
1157 | 0 | break; |
1158 | 699 | case 6: // GLONASS |
1159 | 699 | obs_code = "L1C"; // u-blox calls this L1OF |
1160 | 699 | break; |
1161 | 4.01k | } |
1162 | 4.01k | (void)strlcpy(session->gpsdata.raw.meas[i].obs_code, obs_code, |
1163 | 4.01k | sizeof(session->gpsdata.raw.meas[i].obs_code)); |
1164 | | |
1165 | 4.01k | session->gpsdata.raw.meas[i].svid = svId; |
1166 | 4.01k | session->gpsdata.raw.meas[i].snr = cno; |
1167 | 4.01k | session->gpsdata.raw.meas[i].satstat = trkStat; |
1168 | 4.01k | if (trkStat & 1) { |
1169 | | // prMes valid |
1170 | 1.78k | session->gpsdata.raw.meas[i].pseudorange = prMes; |
1171 | 2.23k | } else { |
1172 | 2.23k | session->gpsdata.raw.meas[i].pseudorange = NAN; |
1173 | 2.23k | } |
1174 | 4.01k | if (trkStat & 2) { |
1175 | | // doppler valid |
1176 | 2.01k | session->gpsdata.raw.meas[i].doppler = doMes; |
1177 | 2.01k | } else { |
1178 | 2.00k | session->gpsdata.raw.meas[i].doppler = NAN; |
1179 | 2.00k | } |
1180 | 4.01k | if (trkStat & 4) { |
1181 | | // cpMes valid |
1182 | 1.67k | session->gpsdata.raw.meas[i].carrierphase = cpMes; |
1183 | 2.34k | } else { |
1184 | 2.34k | session->gpsdata.raw.meas[i].carrierphase = NAN; |
1185 | 2.34k | } |
1186 | 4.01k | session->gpsdata.raw.meas[i].codephase = NAN; |
1187 | 4.01k | session->gpsdata.raw.meas[i].deltarange = NAN; |
1188 | | // skytraq does not report locktime, so assume max |
1189 | 4.01k | session->gpsdata.raw.meas[i].locktime = LOCKMAX; |
1190 | 4.01k | if (trkStat & 8) { |
1191 | | // possible slip |
1192 | 1.74k | session->gpsdata.raw.meas[i].lli = 2; |
1193 | 1.74k | } |
1194 | 4.01k | GPSD_LOG(LOG_DATA, &session->context->errout, |
1195 | 4.01k | "PRN %u (%u:%u) prMes %f cpMes %f doMes %f\n" |
1196 | 4.01k | "cno %u rtkStat %u\n", PRN, |
1197 | 4.01k | gnssId, svId, prMes, cpMes, doMes, cno, trkStat); |
1198 | | |
1199 | 4.01k | } |
1200 | | |
1201 | | // return RAW_IS; // WIP |
1202 | 786 | return 0; |
1203 | 786 | } |
1204 | | |
1205 | | /* |
1206 | | * decode MID 0xDE, SV and channel status |
1207 | | * |
1208 | | * max payload: 3 + (Num_sats * 10) = 483 bytes |
1209 | | */ |
1210 | | static gps_mask_t sky_msg_DE(struct gps_device_t *session, |
1211 | | const unsigned char *buf, const size_t len) |
1212 | 1.56k | { |
1213 | 1.56k | int st, nsv; |
1214 | 1.56k | unsigned i; |
1215 | 1.56k | unsigned iod; // Issue of data 0 - 255 |
1216 | 1.56k | unsigned nsvs; // number of SVs in this packet |
1217 | | |
1218 | 1.56k | if (3 > len) { |
1219 | 246 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1220 | 246 | "Skytraq 0xDE: bad len %zu\n", len); |
1221 | 246 | return 0; |
1222 | 246 | } |
1223 | 1.32k | iod = (unsigned)getub(buf, 1); |
1224 | 1.32k | nsvs = (unsigned)getub(buf, 2); |
1225 | | // too many sats? |
1226 | 1.32k | if (SKY_CHANNELS < nsvs) { |
1227 | 67 | return 0; |
1228 | 67 | } |
1229 | | |
1230 | 1.25k | if (len < (3 + (nsvs * 10))) { |
1231 | 80 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1232 | 80 | "Skytraq 0xDE: bad len %zu\n", len); |
1233 | 80 | return 0; |
1234 | 80 | } |
1235 | 1.17k | gpsd_zero_satellites(&session->gpsdata); |
1236 | 5.37k | for (i = st = nsv = 0; i < nsvs; i++) { |
1237 | 4.20k | int off = 3 + (10 * i); // offset into buffer of start of this sat |
1238 | 4.20k | bool good; // do we have a good record ? |
1239 | 4.20k | unsigned short sv_stat; |
1240 | 4.20k | unsigned short chan_stat; |
1241 | 4.20k | unsigned short ura; |
1242 | 4.20k | short PRN; |
1243 | 4.20k | uint8_t gnssId = 0; |
1244 | 4.20k | uint8_t svId = 0; |
1245 | | |
1246 | 4.20k | PRN = (short)getub(buf, off + 1); |
1247 | | // fit into gnssid:svid |
1248 | 4.20k | if (0 == PRN) { |
1249 | | // skip 0 PRN |
1250 | 396 | continue; |
1251 | 396 | } |
1252 | 3.80k | PRN2_gnssId_svId(PRN, &gnssId, &svId); |
1253 | | |
1254 | 3.80k | session->gpsdata.skyview[st].gnssid = gnssId; |
1255 | 3.80k | session->gpsdata.skyview[st].svid = svId; |
1256 | 3.80k | session->gpsdata.skyview[st].PRN = PRN; |
1257 | | |
1258 | 3.80k | sv_stat = (unsigned short)getub(buf, off + 2); |
1259 | 3.80k | ura = (unsigned short)getub(buf, off + 3); |
1260 | 3.80k | session->gpsdata.skyview[st].ss = (double)getub(buf, off + 4); |
1261 | 3.80k | session->gpsdata.skyview[st].elevation = |
1262 | 3.80k | (double)getbes16(buf, off + 5); |
1263 | 3.80k | session->gpsdata.skyview[st].azimuth = |
1264 | 3.80k | (double)getbes16(buf, off + 7); |
1265 | 3.80k | chan_stat = (unsigned short)getub(buf, off + 9); |
1266 | | |
1267 | 3.80k | session->gpsdata.skyview[st].used = (bool)(chan_stat & 0x30); |
1268 | 3.80k | good = session->gpsdata.skyview[st].PRN != 0 && |
1269 | 3.80k | session->gpsdata.skyview[st].azimuth != 0 && |
1270 | 3.50k | session->gpsdata.skyview[st].elevation != 0; |
1271 | | |
1272 | 3.80k | GPSD_LOG(LOG_DATA, &session->context->errout, |
1273 | 3.80k | "Skytraq PRN=%2d El=%4.0f Az=%5.0f ss=%3.2f stat=%02x,%02x " |
1274 | 3.80k | "ura=%d %c\n", |
1275 | 3.80k | session->gpsdata.skyview[st].PRN, |
1276 | 3.80k | session->gpsdata.skyview[st].elevation, |
1277 | 3.80k | session->gpsdata.skyview[st].azimuth, |
1278 | 3.80k | session->gpsdata.skyview[st].ss, |
1279 | 3.80k | chan_stat, sv_stat, ura, |
1280 | 3.80k | good ? '*' : ' '); |
1281 | | |
1282 | 3.80k | if (good) { |
1283 | 3.21k | st += 1; |
1284 | 3.21k | if (session->gpsdata.skyview[st].used) { |
1285 | 21 | nsv++; |
1286 | 21 | } |
1287 | 3.21k | } |
1288 | 3.80k | } |
1289 | | |
1290 | 1.17k | session->gpsdata.satellites_visible = st; |
1291 | 1.17k | if (MAXCHANNELS < session->gpsdata.satellites_visible) { |
1292 | 4 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1293 | 4 | "Skytraq 0xDE: too many satellites %d\n", |
1294 | 4 | session->gpsdata.satellites_visible); |
1295 | 4 | session->gpsdata.satellites_visible = MAXCHANNELS; |
1296 | 4 | } |
1297 | 1.17k | session->gpsdata.satellites_used = nsv; |
1298 | | |
1299 | 1.17k | GPSD_LOG(LOG_DATA, &session->context->errout, |
1300 | 1.17k | "Skytraq 0xDE: nsvs=%u visible=%u iod=%u\n", nsvs, |
1301 | 1.17k | session->gpsdata.satellites_visible, iod); |
1302 | 1.17k | return SATELLITE_SET | USED_IS; |
1303 | 1.25k | } |
1304 | | |
1305 | | /* |
1306 | | * decode MID 0xDF, Nav status (PVT) |
1307 | | * |
1308 | | * 81 bytes |
1309 | | */ |
1310 | | static gps_mask_t sky_msg_DF(struct gps_device_t *session, |
1311 | | const unsigned char *buf, const size_t len) |
1312 | 81 | { |
1313 | 81 | unsigned short navstat; |
1314 | 81 | unsigned iod; // Issue of data 0 - 255 |
1315 | 81 | unsigned wn; // week number 0 - 65535 |
1316 | 81 | double f_tow; // receiver tow Sec |
1317 | 81 | double clock_bias; |
1318 | 81 | double clock_drift; |
1319 | 81 | gps_mask_t mask = 0; |
1320 | 81 | timespec_t ts_tow; |
1321 | 81 | char ts_buf[TIMESPEC_LEN]; |
1322 | | |
1323 | 81 | if (81 != len) { |
1324 | 76 | return 0; |
1325 | 76 | } |
1326 | | |
1327 | 5 | iod = (unsigned)getub(buf, 1); |
1328 | | |
1329 | | // fix status is byte 2 |
1330 | 5 | navstat = (unsigned short)getub(buf, 2); |
1331 | 5 | session->newdata.status = STATUS_UNK; |
1332 | 5 | session->newdata.mode = MODE_NO_FIX; |
1333 | 5 | switch (navstat) { |
1334 | 0 | case 1: |
1335 | | // fix prediction, ignore |
1336 | 0 | break; |
1337 | 0 | case 2: |
1338 | 0 | session->newdata.status = STATUS_GPS; |
1339 | 0 | session->newdata.mode = MODE_2D; |
1340 | 0 | break; |
1341 | 1 | case 3: |
1342 | 1 | session->newdata.status = STATUS_GPS; |
1343 | 1 | session->newdata.mode = MODE_3D; |
1344 | 1 | break; |
1345 | 0 | case 4: |
1346 | 0 | session->newdata.status = STATUS_DGPS; |
1347 | 0 | session->newdata.mode = MODE_3D; |
1348 | 0 | break; |
1349 | 4 | default: |
1350 | 4 | break; |
1351 | 5 | } |
1352 | | |
1353 | 5 | wn = getbeu16(buf, 3); |
1354 | 5 | f_tow = getbed64((const char *)buf, 5); |
1355 | 5 | DTOTS(&ts_tow, f_tow); |
1356 | | |
1357 | | // position/velocity is bytes 13-48, meters and m/s |
1358 | 5 | session->newdata.ecef.x = (double)getbed64((const char *)buf, 13), |
1359 | 5 | session->newdata.ecef.y = (double)getbed64((const char *)buf, 21), |
1360 | 5 | session->newdata.ecef.z = (double)getbed64((const char *)buf, 29), |
1361 | 5 | session->newdata.ecef.vx = (double)getbef32((const char *)buf, 37), |
1362 | 5 | session->newdata.ecef.vy = (double)getbef32((const char *)buf, 41), |
1363 | 5 | session->newdata.ecef.vz = (double)getbef32((const char *)buf, 45); |
1364 | 5 | mask |= ECEF_SET | VECEF_SET; |
1365 | | |
1366 | 5 | clock_bias = getbed64((const char *)buf, 49); |
1367 | 5 | clock_drift = getbes32(buf, 57); |
1368 | | |
1369 | 5 | session->gpsdata.dop.gdop = getbef32((const char *)buf, 61); |
1370 | 5 | session->gpsdata.dop.pdop = getbef32((const char *)buf, 65); |
1371 | 5 | session->gpsdata.dop.hdop = getbef32((const char *)buf, 69); |
1372 | 5 | session->gpsdata.dop.vdop = getbef32((const char *)buf, 73); |
1373 | 5 | session->gpsdata.dop.tdop = getbef32((const char *)buf, 77); |
1374 | 5 | mask |= DOP_SET; |
1375 | | |
1376 | 5 | session->newdata.time = gpsd_gpstime_resolv(session, wn, ts_tow ); |
1377 | | |
1378 | 5 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1379 | 5 | "Skytraq 0xDF: iod=%u, stat=%u, wn=%u, tow=%f, t=%s " |
1380 | 5 | "cb: %f, cd: %f " |
1381 | 5 | "gdop: %.2f, pdop: %.2f, hdop: %.2f, vdop: %.2f, tdop: %.2f\n", |
1382 | 5 | iod, navstat, wn, f_tow, |
1383 | 5 | timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)), |
1384 | 5 | clock_bias, clock_drift, |
1385 | 5 | session->gpsdata.dop.gdop, |
1386 | 5 | session->gpsdata.dop.pdop, |
1387 | 5 | session->gpsdata.dop.hdop, |
1388 | 5 | session->gpsdata.dop.vdop, |
1389 | 5 | session->gpsdata.dop.tdop); |
1390 | | |
1391 | 5 | mask |= TIME_SET | STATUS_SET | MODE_SET | CLEAR_IS | REPORT_IS; |
1392 | 5 | return mask; |
1393 | 5 | } |
1394 | | |
1395 | | /* |
1396 | | * decode MID 0xE0, GPS Subframe data |
1397 | | * |
1398 | | * len 33 bytes |
1399 | | * |
1400 | | */ |
1401 | | static gps_mask_t sky_msg_E0(struct gps_device_t *session, |
1402 | | const unsigned char *buf, const size_t len) |
1403 | 330 | { |
1404 | 330 | int i; |
1405 | 330 | unsigned prn; // GPS sat PRN |
1406 | 330 | unsigned subf; // subframe 1-5 |
1407 | | // the words are preprocessed, not raw, just the 24bits of data |
1408 | 330 | uint32_t words[10]; // subframe 1-5 |
1409 | | |
1410 | 330 | if (33 != len) { |
1411 | 75 | return 0; |
1412 | 75 | } |
1413 | | |
1414 | 255 | prn = (unsigned)getub(buf, 1); |
1415 | 255 | subf = (unsigned)getub(buf, 2); |
1416 | 2.80k | for (i = 0; i < 10; i++) { |
1417 | 2.55k | words[i] = (uint32_t)getbeu24(buf, 3 + (i * 3)); |
1418 | 2.55k | } |
1419 | | |
1420 | 255 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1421 | 255 | "Skytraq 0xE0: prn=%u, subf=%u\n", |
1422 | 255 | prn, subf); |
1423 | | |
1424 | | // could be SBAS? |
1425 | 255 | return gpsd_interpret_subframe(session, GNSSID_GPS, prn, words); |
1426 | 330 | } |
1427 | | |
1428 | | /* |
1429 | | * pretend to decode MID 0xE2, Beiduo D1 Subframe data |
1430 | | * |
1431 | | * from Beidou Standard BDS-SIS-ICD-2.0 |
1432 | | * D1, with the data rate of 50 bps, is broadcasted by the MEO/IGSO satellites |
1433 | | * |
1434 | | * len 31 bytes |
1435 | | * |
1436 | | */ |
1437 | | static gps_mask_t sky_msg_E2(struct gps_device_t *session, |
1438 | | const unsigned char *buf, const size_t len) |
1439 | 72 | { |
1440 | 72 | int i; |
1441 | 72 | unsigned prn; // BeidouPS sat PRN 206-214 |
1442 | 72 | unsigned subf; // subframe 1-5 |
1443 | | // the words are preprocessed, not raw, just the 28 bytes of data |
1444 | 72 | uint8_t bytes[28]; // raw data |
1445 | | |
1446 | 72 | if (31 != len) { |
1447 | 71 | return 0; |
1448 | 71 | } |
1449 | | |
1450 | 1 | prn = (unsigned)getub(buf, 1); |
1451 | 1 | subf = (unsigned)getub(buf, 2); |
1452 | 29 | for (i = 0; i < 28; i++) { |
1453 | 28 | bytes[i] = getub(buf, 3 + i); |
1454 | 28 | } |
1455 | | |
1456 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1457 | 1 | "Skytraq Beidou D1 subframe PRN %d Subframe %d " |
1458 | 1 | "length %zd byte:%s\n", |
1459 | 1 | prn, subf, len, |
1460 | 1 | gps_hexdump(session->msgbuf, sizeof(session->msgbuf), |
1461 | 1 | bytes, 28)); |
1462 | | |
1463 | 1 | return ONLINE_SET; |
1464 | 72 | } |
1465 | | |
1466 | | /* |
1467 | | * pretend to decode MID 0xE3, Beiduo D2 Subframe data |
1468 | | * |
1469 | | * from Beidou Standard BDS-SIS-ICD-2.0 |
1470 | | * D2, with the data rate of 500 bps, is broadcasted by the GEO satellites. |
1471 | | * |
1472 | | * len 31 bytes |
1473 | | * |
1474 | | */ |
1475 | | static gps_mask_t sky_msg_E3(struct gps_device_t *session, |
1476 | | const unsigned char *buf, const size_t len) |
1477 | 304 | { |
1478 | 304 | int i; |
1479 | 304 | unsigned prn; // BeidouPS sat PRN 201-205 |
1480 | 304 | unsigned subf; // subframe 1-5 |
1481 | | // the words are preprocessed, not raw, just the 28 bytes of data |
1482 | 304 | uint8_t bytes[28]; // raw data |
1483 | | |
1484 | 304 | if (31 != len) { |
1485 | 303 | return 0; |
1486 | 303 | } |
1487 | | |
1488 | 1 | prn = (unsigned)getub(buf, 1); |
1489 | 1 | subf = (unsigned)getub(buf, 2); |
1490 | 29 | for (i = 0; i < 28; i++) { |
1491 | 28 | bytes[i] = getub(buf, 3 + i); |
1492 | 28 | } |
1493 | | |
1494 | 1 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1495 | 1 | "Skytraq Beidou D2 subframe PRN %d Subframe %d " |
1496 | 1 | "length %zd byte:%s\n", |
1497 | 1 | prn, subf, len, |
1498 | 1 | gps_hexdump(session->msgbuf, sizeof(session->msgbuf), |
1499 | 1 | bytes, 28)); |
1500 | | |
1501 | 1 | return ONLINE_SET; |
1502 | 304 | } |
1503 | | |
1504 | | |
1505 | | static gps_mask_t sky_parse(struct gps_device_t * session, |
1506 | | unsigned char *buf, size_t len) |
1507 | 12.2k | { |
1508 | 12.2k | gps_mask_t mask = 0; |
1509 | | |
1510 | 12.2k | if (0 == len) { |
1511 | 0 | return mask; |
1512 | 0 | } |
1513 | | |
1514 | 12.2k | buf += 4; // skip the leaders and length |
1515 | 12.2k | len -= 7; // don't count the leaders, length, csum and terminators |
1516 | | // session->driver.sirf.lastid = buf[0]; |
1517 | | |
1518 | | // check the checksum?? |
1519 | | |
1520 | | // could change if the set of messages we enable does |
1521 | | // session->cycle_end_reliable = true; |
1522 | | |
1523 | 12.2k | switch (buf[0]) { |
1524 | 589 | case 0x62: |
1525 | 589 | mask = sky_msg_62(session, buf, len); |
1526 | 589 | break; |
1527 | 696 | case 0x63: |
1528 | 696 | mask = sky_msg_63(session, buf, len); |
1529 | 696 | break; |
1530 | 1.05k | case 0x64: |
1531 | 1.05k | mask = sky_msg_64(session, buf, len); |
1532 | 1.05k | break; |
1533 | 339 | case 0x65: |
1534 | 339 | mask = sky_msg_65(session, buf, len); |
1535 | 339 | break; |
1536 | 300 | case 0x6A: |
1537 | 300 | mask = sky_msg_6A(session, buf, len); |
1538 | 300 | break; |
1539 | 327 | case 0x7A: |
1540 | 327 | mask = sky_msg_7A(session, buf, len); |
1541 | 327 | break; |
1542 | 171 | case 0x80: |
1543 | | // 128 |
1544 | 171 | mask = sky_msg_80(session, buf, len); |
1545 | 171 | break; |
1546 | 68 | case 0x81: |
1547 | | // Software CRC |
1548 | 68 | mask = sky_msg_81(session, buf, len); |
1549 | 68 | break; |
1550 | 713 | case 0x83: |
1551 | | // 131 - ACK |
1552 | 713 | if (2 == len) { |
1553 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1554 | 67 | "Skytraq 0x83: ACK MID %#02x\n", buf[1]); |
1555 | 646 | } else if (3 == len) { |
1556 | 69 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1557 | 69 | "Skytraq 0x83: ACK MID %#02x/%02x\n", buf[1], buf[2]); |
1558 | 577 | } else if (4 <= len) { |
1559 | 452 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1560 | 452 | "Skytraq 0x83: ACK MID %#02x/%02x/%02x\n", |
1561 | 452 | buf[1], buf[2], buf[3]); |
1562 | 452 | } else { |
1563 | 125 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1564 | 125 | "Skytraq 0x83: ACK\n"); |
1565 | 125 | } |
1566 | 713 | break; |
1567 | 448 | case 0x84: |
1568 | | // 132 - NACK |
1569 | 448 | if (2 == len) { |
1570 | 69 | GPSD_LOG(LOG_INF, &session->context->errout, |
1571 | 69 | "Skytraq 0x84: NACK MID %#02x\n", buf[1]); |
1572 | 379 | } else if (3 == len) { |
1573 | 98 | GPSD_LOG(LOG_INF, &session->context->errout, |
1574 | 98 | "Skytraq 0x84: NACK MID %#02x/%02x\n", buf[1], buf[2]); |
1575 | 281 | } else if (4 <= len) { |
1576 | 69 | GPSD_LOG(LOG_INF, &session->context->errout, |
1577 | 69 | "Skytraq 0x84: NACK MID %#02x/%02x/x%02x\n", |
1578 | 69 | buf[1], buf[2], buf[3]); |
1579 | 212 | } else { |
1580 | 212 | GPSD_LOG(LOG_INF, &session->context->errout, |
1581 | 212 | "Skytraq 0x84: NACK\n"); |
1582 | 212 | } |
1583 | 448 | break; |
1584 | 168 | case 0x86: |
1585 | | // 134 Position Update Rate |
1586 | 168 | mask = sky_msg_86(session, buf, len); |
1587 | 168 | break; |
1588 | 120 | case 0x89: |
1589 | 120 | mask = sky_msg_89(session, buf, len); |
1590 | 120 | break; |
1591 | 489 | case 0x8A: |
1592 | 489 | mask = sky_msg_8A(session, buf, len); |
1593 | 489 | break; |
1594 | 172 | case 0x8B: |
1595 | 172 | mask = sky_msg_8B(session, buf, len); |
1596 | 172 | break; |
1597 | 154 | case 0x93: |
1598 | | // NMEA TALKER id |
1599 | 154 | mask = sky_msg_93(session, buf, len); |
1600 | 154 | break; |
1601 | | |
1602 | 90 | case 0xA8: |
1603 | | // Navigation Data Message |
1604 | 90 | mask = sky_msg_A8(session, buf, len); |
1605 | 90 | break; |
1606 | | |
1607 | 1.02k | case 0xae: |
1608 | | // GNSS Datum |
1609 | 1.02k | mask = sky_msg_AE(session, buf, len); |
1610 | 1.02k | break; |
1611 | | |
1612 | 139 | case 0xaf: |
1613 | | // DOP Mask |
1614 | 139 | mask = sky_msg_AF(session, buf, len); |
1615 | 139 | break; |
1616 | | |
1617 | 93 | case 0xb0: |
1618 | | // Elevation and CNR mask |
1619 | 93 | mask = sky_msg_B0(session, buf, len); |
1620 | 93 | break; |
1621 | | |
1622 | 79 | case 0xb4: |
1623 | | // Position Pinning Status |
1624 | 79 | mask = sky_msg_B4(session, buf, len); |
1625 | 79 | break; |
1626 | | |
1627 | 321 | case 0xb9: |
1628 | 321 | mask = sky_msg_B9(session, buf, len); |
1629 | 321 | break; |
1630 | | |
1631 | 69 | case 0xbb: |
1632 | 69 | mask = sky_msg_BB(session, buf, len); |
1633 | 69 | break; |
1634 | | |
1635 | 271 | case 0xDC: |
1636 | | // 220 |
1637 | 271 | mask = sky_msg_DC(session, buf, len); |
1638 | 271 | break; |
1639 | | |
1640 | 1.03k | case 0xDD: |
1641 | | // 221 |
1642 | 1.03k | if (3 <= len) { |
1643 | 895 | mask = sky_msg_DD(session, buf, len); |
1644 | 895 | } |
1645 | 1.03k | break; |
1646 | | |
1647 | 1.56k | case 0xDE: |
1648 | | // 222 |
1649 | 1.56k | mask = sky_msg_DE(session, buf, len); |
1650 | 1.56k | break; |
1651 | | |
1652 | 81 | case 0xDF: |
1653 | | // 223 - Nave status (PVT) |
1654 | 81 | mask = sky_msg_DF(session, buf, len); |
1655 | 81 | break; |
1656 | | |
1657 | 330 | case 0xE0: |
1658 | | // 224 |
1659 | 330 | mask = sky_msg_E0(session, buf, len); |
1660 | 330 | break; |
1661 | | |
1662 | 72 | case 0xE2: |
1663 | | // 226 - Beidou2 D1 Subframe data |
1664 | 72 | mask = sky_msg_E2(session, buf, len); |
1665 | 72 | break; |
1666 | | |
1667 | 304 | case 0xE3: |
1668 | | // 227 - Beidou2 D2 Subframe data |
1669 | 304 | mask = sky_msg_E3(session, buf, len); |
1670 | 304 | break; |
1671 | | |
1672 | 134 | case 0x67: // sub-id messages |
1673 | 134 | FALLTHROUGH |
1674 | 234 | case 0x6F: // sub-id messages |
1675 | 234 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1676 | 234 | "Skytraq Unknown MID x%02x SID x%02x length %zd\n", |
1677 | 234 | buf[0], buf[1], len); |
1678 | 234 | break; |
1679 | 718 | default: |
1680 | 718 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1681 | 718 | "Skytraq Unknown MID %#02x length %zd\n", |
1682 | 718 | buf[0], len); |
1683 | 718 | break; |
1684 | 12.2k | } |
1685 | 12.2k | return mask; |
1686 | 12.2k | } |
1687 | | |
1688 | | static gps_mask_t skybin_parse_input(struct gps_device_t *session) |
1689 | 14.1k | { |
1690 | | /* |
1691 | | * Use this hook to step, slowly, through the init messages. |
1692 | | * By sending only one for each three received we try |
1693 | | * to avoid overrunning the receiver input buffer. |
1694 | | */ |
1695 | | |
1696 | 14.1k | if (UINT_MAX != session->cfg_stage) { |
1697 | 8.05k | session->cfg_step++; |
1698 | 8.05k | } |
1699 | | |
1700 | 14.1k | if (UINT_MAX != session->cfg_stage && |
1701 | 8.05k | 3 <= session->cfg_step) { |
1702 | | // more init to do |
1703 | | |
1704 | 2.68k | session->cfg_stage++; |
1705 | 2.68k | session->cfg_step = 0; |
1706 | | |
1707 | | // Note: the checksums in the Skytaq doc are sometimes wrong... |
1708 | | |
1709 | | // drivers/driver_nmea0183.c send 0x04 to get MID 0x80 on detect |
1710 | | |
1711 | | // FIXME: make a table |
1712 | 2.68k | switch (session->cfg_stage) { |
1713 | 132 | case 1: |
1714 | | // Send MID 0x3, to get back MID 0x81 Software CRC |
1715 | 132 | (void)sky_write(session, "\xA0\xA1\x00\x02\x03\x00\x03\x0d\x0a", |
1716 | 132 | 9); |
1717 | 132 | break; |
1718 | 119 | case 2: |
1719 | | // Send MID 0x10, to get back MID 0x86 (Position Update Rate) |
1720 | 119 | (void)sky_write(session, "\xA0\xA1\x00\x01\x10\x10\x0d\x0a", 8); |
1721 | 119 | break; |
1722 | 141 | case 3: |
1723 | | // Send MID 0x15, to get back MID 0xB9 (Power Mode Status) |
1724 | 141 | (void)sky_write(session, "\xA0\xA1\x00\x01\x15\x15\x0d\x0a", 8); |
1725 | 141 | break; |
1726 | 112 | case 4: |
1727 | | // Send MID 0x1f, to get back MID 0x89 Measurement data statuS |
1728 | 112 | (void)sky_write(session, "\xA0\xA1\x00\x01\x1f\x1f\x0d\x0a", 8); |
1729 | 112 | break; |
1730 | 116 | case 5: |
1731 | | // Send MID 0x21, to get back MID 0x8a RTCM Data output status |
1732 | 116 | (void)sky_write(session, "\xA0\xA1\x00\x01\x21\x21\x0d\x0a", 8); |
1733 | 116 | break; |
1734 | 110 | case 6: |
1735 | | // Send MID 0x23, to get back MID 0x8B (Base Position) |
1736 | 110 | (void)sky_write(session, "\xA0\xA1\x00\x01\x23\x23\x0d\x0a", 8); |
1737 | 110 | break; |
1738 | 98 | case 7: |
1739 | | // Send MID 0x2d, to get back MID 0xAE (GNSS Datum) |
1740 | 98 | (void)sky_write(session, "\xA0\xA1\x00\x01\x2d\x2d\x0d\x0a", 8); |
1741 | 98 | break; |
1742 | 103 | case 8: |
1743 | | // Send MID 0x2E, to get back MID 0xAF (DOP Mask) |
1744 | 103 | (void)sky_write(session, "\xA0\xA1\x00\x01\x2e\x2e\x0d\x0a", 8); |
1745 | 103 | break; |
1746 | 96 | case 9: |
1747 | | // Send MID 0x2F, to get back MID 0x80 Elevation and SNR mask |
1748 | 96 | (void)sky_write(session, "\xA0\xA1\x00\x01\x2f\x2f\x0d\x0a", 8); |
1749 | 96 | break; |
1750 | 92 | case 10: |
1751 | | // Send MID 0x3a, to get back MID 0xb4 Position Pinning |
1752 | 92 | (void)sky_write(session, "\xA0\xA1\x00\x01\x3a\x3a\x0d\x0a", 8); |
1753 | 92 | break; |
1754 | 90 | case 11: |
1755 | | // Send MID 0x44, to get back MID 0xc2 1PPS timing |
1756 | | // Timing mode versions only |
1757 | 90 | (void)sky_write(session, "\xA0\xA1\x00\x01\x44\x44\x0d\x0a", 8); |
1758 | 90 | break; |
1759 | 101 | case 12: |
1760 | | // Send MID 0x46, to get back MID 0xbb 1PPS delay |
1761 | 101 | (void)sky_write(session, "\xA0\xA1\x00\x01\x46\x46\x0d\x0a", 8); |
1762 | 101 | break; |
1763 | 95 | case 13: |
1764 | | // Send MID 0x4f, to get back MID 0x93 NMEA talker ID |
1765 | 95 | (void)sky_write(session, "\xA0\xA1\x00\x01\x4f\x4f\x0d\x0a", 8); |
1766 | 95 | break; |
1767 | 86 | case 14: |
1768 | | // Send MID 0x56, to get back MID 0xc3 1PPS Output Mode |
1769 | | // Timing mode versions only |
1770 | 86 | (void)sky_write(session, "\xA0\xA1\x00\x01\x56\x56\x0d\x0a", 8); |
1771 | 86 | break; |
1772 | 81 | case 15: |
1773 | | // Send MID 0x62/02, to get back MID 0x62/80 SBAS status |
1774 | 81 | (void)sky_write(session, |
1775 | 81 | "\xA0\xA1\x00\x02\x62\x02\x60\x0d\x0a", 9); |
1776 | 81 | break; |
1777 | 76 | case 16: |
1778 | | // Send MID 0x62/04, to get back MID 0x62/81 QZSS status |
1779 | 76 | (void)sky_write(session, |
1780 | 76 | "\xA0\xA1\x00\x02\x62\x04\x66\x0d\x0a", 9); |
1781 | 76 | break; |
1782 | 72 | case 17: |
1783 | | // Send MID 0x62/06, to get back MID 0x62/82 SBAS Advanced status |
1784 | 72 | (void)sky_write(session, |
1785 | 72 | "\xA0\xA1\x00\x02\x62\x06\x64\x0d\x0a", 9); |
1786 | 72 | break; |
1787 | 65 | case 18: |
1788 | | // Send MID 0x63/02, to get back MID 0x62/80 SAEE Status |
1789 | | // not on PX1172RH_DS |
1790 | 65 | (void)sky_write(session, |
1791 | 65 | "\xA0\xA1\x00\x02\x63\x02\x61\x0d\x0a", 9); |
1792 | 65 | break; |
1793 | 58 | case 19: |
1794 | | // Send MID 0x64/01, to get back MID 0x64/80 |
1795 | 58 | (void)sky_write(session, |
1796 | 58 | "\xA0\xA1\x00\x02\x64\x01\x65\x0d\x0a", 9); |
1797 | 58 | break; |
1798 | 53 | case 20: |
1799 | | // Send MID 0x64/03, to get back MID 0x64/81 |
1800 | 53 | (void)sky_write(session, |
1801 | 53 | "\xA0\xA1\x00\x02\x64\x03\x67\x0d\x0a", 9); |
1802 | 53 | break; |
1803 | 51 | case 21: |
1804 | | // Send MID 0x64/07, to get back MID 0x64/83 |
1805 | 51 | (void)sky_write(session, |
1806 | 51 | "\xA0\xA1\x00\x02\x64\x07\x63\x0d\x0a", 9); |
1807 | 51 | break; |
1808 | 46 | case 22: |
1809 | | // Send MID 0x64/0b, to get back MID 0x64/85 |
1810 | 46 | (void)sky_write(session, |
1811 | 46 | "\xA0\xA1\x00\x02\x64\x0b\x6f\x0d\x0a", 9); |
1812 | 46 | break; |
1813 | 43 | case 23: |
1814 | | // Send MID 0x64/12, to get back MID 0x64/88 |
1815 | 43 | (void)sky_write(session, |
1816 | 43 | "\xA0\xA1\x00\x02\x64\x12\x76\x0d\x0a", 9); |
1817 | 43 | break; |
1818 | 41 | case 24: |
1819 | | // Send MID 0x64/16, to get back MID 0x64/8a |
1820 | 41 | (void)sky_write(session, |
1821 | 41 | "\xA0\xA1\x00\x02\x64\x16\x72\x0d\x0a", 9); |
1822 | 41 | break; |
1823 | 41 | case 25: |
1824 | | // Send MID 0x64/18, to get back MID 0x64/8b |
1825 | 41 | (void)sky_write(session, |
1826 | 41 | "\xA0\xA1\x00\x02\x64\x18\x7c\x0d\x0a", 9); |
1827 | 41 | break; |
1828 | 40 | case 26: |
1829 | | // Send MID 0x64/1a, to get back MID 0x64/8c |
1830 | 40 | (void)sky_write(session, |
1831 | 40 | "\xA0\xA1\x00\x02\x64\x1a\x7e\x0d\x0a", 9); |
1832 | 40 | break; |
1833 | 39 | case 27: |
1834 | | // Send MID 0x64/20, to get back MID 0x64/8e |
1835 | 39 | (void)sky_write(session, |
1836 | 39 | "\xA0\xA1\x00\x02\x64\x20\x44\x0d\x0a", 9); |
1837 | 39 | break; |
1838 | 38 | case 28: |
1839 | | // Send MID 0x64/22, to get back MID 0x64/8f |
1840 | | // not on PX1172RH_DS |
1841 | 38 | (void)sky_write(session, |
1842 | 38 | "\xA0\xA1\x00\x02\x64\x22\x46\x0d\x0a", 9); |
1843 | 38 | break; |
1844 | 37 | case 29: |
1845 | | // Send MID 0x64/28, to get back MID 0x64/92 |
1846 | 37 | (void)sky_write(session, |
1847 | 37 | "\xA0\xA1\x00\x02\x64\x28\x4c\x0d\x0a", 9); |
1848 | 37 | break; |
1849 | 35 | case 30: |
1850 | | // Send MID 0x64/30, to get back MID 0x64/98 |
1851 | | // not on PX1172RH_DS |
1852 | 35 | (void)sky_write(session, |
1853 | 35 | "\xA0\xA1\x00\x02\x64\x30\x54\x0d\x0a", 9); |
1854 | 35 | break; |
1855 | 34 | case 31: |
1856 | | // Send MID 0x64/31, to get back MID 0x64/ |
1857 | | // not on PX1172RH_DS |
1858 | 34 | (void)sky_write(session, |
1859 | 34 | "\xA0\xA1\x00\x02\x64\x31\x55\x0d\x0a", 9); |
1860 | 34 | break; |
1861 | 33 | case 32: |
1862 | | // Send MID 0x64/7d, to get back MID 0x64/fe |
1863 | 33 | (void)sky_write(session, |
1864 | 33 | "\xA0\xA1\x00\x02\x64\x7d\x19\x0d\x0a", 9); |
1865 | 33 | break; |
1866 | 32 | case 33: |
1867 | | // Send MID 0x64/35, to get back MID 0x64/99 |
1868 | | // not on PX1172RH_DS |
1869 | 32 | (void)sky_write(session, |
1870 | 32 | "\xA0\xA1\x00\x03\x64\x35\x01\x50\x0d\x0a", 10); |
1871 | 32 | break; |
1872 | 29 | case 34: |
1873 | | // Send MID 0x64/36, to get back MID 0x64/9a |
1874 | | // not on PX1172RH_DS |
1875 | 29 | (void)sky_write(session, |
1876 | 29 | "\xA0\xA1\x00\x02\x64\x36\x52\x0d\x0a", 9); |
1877 | 29 | break; |
1878 | 26 | case 35: |
1879 | | // Send MID 0x64/3c, to get back MID 0x64/99 |
1880 | | // not on PX1172RH_DS |
1881 | 26 | (void)sky_write(session, |
1882 | 26 | "\xA0\xA1\x00\x04\x64\x3c\x47\x47\x19\x0d\x0a", |
1883 | 26 | 11); |
1884 | 26 | break; |
1885 | 24 | case 36: |
1886 | | // Send MID 0x65/02, to get back MID 0x64/80 |
1887 | 24 | (void)sky_write(session, |
1888 | 24 | "\xA0\xA1\x00\x02\x65\x02\x67\x0d\x0a", 9); |
1889 | 24 | break; |
1890 | 23 | case 37: |
1891 | | // Send MID 0x65/04, to get back MID 0x64/8f |
1892 | 23 | (void)sky_write(session, |
1893 | 23 | "\xA0\xA1\x00\x02\x65\x04\x61\x0d\x0a", 9); |
1894 | 23 | break; |
1895 | 22 | case 38: |
1896 | | // Send MID 0x6a/02, to get back MID 0x6a/83 |
1897 | 22 | (void)sky_write(session, |
1898 | 22 | "\xA0\xA1\x00\x02\x6a\x02\x68\x0d\x0a", 9); |
1899 | 22 | break; |
1900 | 21 | case 39: |
1901 | | // Send MID 0x6a/07, to get back MID 0x6a/83 |
1902 | 21 | (void)sky_write(session, |
1903 | 21 | "\xA0\xA1\x00\x02\x6a\x07\x6d\x0d\x0a", 9); |
1904 | 21 | break; |
1905 | 19 | case 40: |
1906 | | // Send MID 0x6a/0d, to get back MID 0x6a/85 |
1907 | 19 | (void)sky_write(session, |
1908 | 19 | "\xA0\xA1\x00\x02\x6a\x0d\x67\x0d\x0a", 9); |
1909 | 19 | break; |
1910 | 19 | case 41: |
1911 | | // Send MID 0x6a/14, to get back MID 0x6a/86 |
1912 | 19 | (void)sky_write(session, |
1913 | 19 | "\xA0\xA1\x00\x02\x6a\x14\xfd\x0d\x0a", 9); |
1914 | 19 | break; |
1915 | 18 | case 42: |
1916 | | // Send MID 0x6a/16, to get back MID 0x6a/89 |
1917 | | // not on PX1172RH_DS ? |
1918 | 18 | (void)sky_write(session, |
1919 | 18 | "\xA0\xA1\x00\x02\x6a\x16\x7c\x0d\x0a", 9); |
1920 | 18 | break; |
1921 | 16 | case 43: |
1922 | | // Send MID 0x7a/0e/01, to get back MID 0x7a/0e/80 |
1923 | | // not on PX1172RH_DS ? |
1924 | 16 | (void)sky_write(session, |
1925 | 16 | "\xA0\xA1\x00\x03\x7a\x0e\x01\x75\x0d\x0a", 10); |
1926 | 16 | break; |
1927 | 15 | case 44: |
1928 | | // Send MID 0x7a/0e/02, to get back MID 0x7a/0e/81 |
1929 | | // not on PX1172RH_DS ? |
1930 | 15 | (void)sky_write(session, |
1931 | 15 | "\xA0\xA1\x00\x03\x7a\x0e\x02\x76\x0d\x0a", 10); |
1932 | 15 | break; |
1933 | 14 | case 45: |
1934 | | // Send MID 0x7a/0e/03, to get back MID 0x7a/0e/82 |
1935 | | // not on PX1172RH_DS ? |
1936 | 14 | (void)sky_write(session, |
1937 | 14 | "\xA0\xA1\x00\x03\x7a\x0e\x03\x77\x0d\x0a", 10); |
1938 | 14 | break; |
1939 | 14 | case 46: |
1940 | | // Send MID 0x7a/0e/05, to get back MID 0x7a/0e/83 |
1941 | | // not on PX1172RH_DS ? |
1942 | 14 | (void)sky_write(session, |
1943 | 14 | "\xA0\xA1\x00\x03\x7a\x0e\x05\x71\x0d\x0a", 10); |
1944 | 14 | break; |
1945 | 14 | default: |
1946 | | // Done |
1947 | 14 | session->cfg_stage = UINT_MAX; |
1948 | 14 | break; |
1949 | 2.68k | } |
1950 | 2.68k | } |
1951 | | |
1952 | 14.1k | if (SKY_PACKET == session->lexer.type) { |
1953 | 12.2k | return sky_parse(session, session->lexer.outbuffer, |
1954 | 12.2k | session->lexer.outbuflen); |
1955 | 12.2k | } |
1956 | 1.96k | if (NMEA_PACKET == session->lexer.type) { |
1957 | 1.96k | return nmea_parse((char *)session->lexer.outbuffer, session); |
1958 | 1.96k | } |
1959 | | // should not get here... |
1960 | | |
1961 | 0 | return 0; |
1962 | 1.96k | } |
1963 | | |
1964 | | // this is everything we export |
1965 | | // *INDENT-OFF* |
1966 | | const struct gps_type_t driver_skytraq = |
1967 | | { |
1968 | | .channels = SKY_CHANNELS, // consumer-grade GPS |
1969 | | .control_send = sky_write, // how to send a control string |
1970 | | .event_hook = NULL, // lifetime event handler |
1971 | | .flags = DRIVER_STICKY, // remember this |
1972 | | .get_packet = packet_get1, // be prepared for Skytraq or NMEA |
1973 | | .init_query = NULL, // non-perturbing initial query |
1974 | | .mode_switcher = sky_mode, // Mode switcher |
1975 | | .packet_type = SKY_PACKET, // associated lexer packet type |
1976 | | .parse_packet = skybin_parse_input, // parse message packets |
1977 | | .probe_detect = NULL, // no probe |
1978 | | .rtcm_writer = gpsd_write, // send RTCM data straight |
1979 | | .trigger = NULL, // no trigger |
1980 | | .type_name = "Skytraq", // full name of type |
1981 | | }; |
1982 | | // *INDENT-ON* |
1983 | | #endif // defined SKYTRAQ_ENABLE) |
1984 | | |
1985 | | // vim: set expandtab shiftwidth=4 |