/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.13k | #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 | 3.31k | { |
54 | 3.31k | uint8_t chk; |
55 | 3.31k | uint16_t len; |
56 | 3.31k | ssize_t i; |
57 | 3.31k | bool ok; |
58 | 3.31k | unsigned type = (unsigned)msg[4]; |
59 | 3.31k | uint8_t buf[BUFSIZ]; |
60 | 3.31k | uint8_t outbuf[BUFSIZ]; |
61 | | |
62 | | // do not write if -b (readonly) option set |
63 | | // "passive" handled earlier |
64 | 3.31k | if (session->context->readonly) { |
65 | 879 | return data_len; |
66 | 879 | } |
67 | | |
68 | 2.43k | 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.43k | memcpy(buf, msg, data_len); |
74 | | |
75 | | // max length is undocumented, largest I could find is 261 |
76 | 2.43k | len = (buf[2] << 8) | buf[3]; |
77 | | // limit to 512 to pacify coverity |
78 | 2.43k | if (512 < len) { |
79 | 0 | len = 512; |
80 | 0 | } |
81 | 2.43k | 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.43k | chk = 0; |
93 | | // coverity_submit[tainted_data] |
94 | 6.00k | for (i = 0; i < len; i++) { |
95 | 3.57k | chk ^= buf[4 + i]; |
96 | 3.57k | } |
97 | | |
98 | | // enter checksum after payload |
99 | 2.43k | buf[len + 4] = chk; |
100 | 2.43k | len += 7; |
101 | | |
102 | 2.43k | GPSD_LOG(LOG_IO, &session->context->errout, |
103 | 2.43k | "Skytraq: Writing control MID %02x: %s\n", type, |
104 | 2.43k | gps_hexdump((char *)outbuf, sizeof(outbuf), buf, len)); |
105 | 2.43k | ok = gpsd_write(session, (const char *)buf, len) == len; |
106 | | |
107 | 2.43k | return ok; |
108 | 2.43k | } |
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 | 6.25k | { |
146 | | // fit into gnssid:svid |
147 | 6.25k | if (0 == PRN) { |
148 | | // skip 0 PRN |
149 | 597 | *gnssId = 0; |
150 | 597 | *svId = 0; |
151 | 5.66k | } else if ((1 <= PRN) && |
152 | 5.66k | (32 >= PRN)) { |
153 | | // GPS |
154 | 772 | *gnssId = 0; |
155 | 772 | *svId = PRN; |
156 | 4.89k | } else if ((65 <= PRN) && |
157 | 4.16k | (96 >= PRN)) { |
158 | | // GLONASS |
159 | 1.08k | *gnssId = 6; |
160 | 1.08k | *svId = PRN - 64; |
161 | 3.80k | } else if ((120 <= PRN) && |
162 | 2.67k | (158 >= PRN)) { |
163 | | // SBAS |
164 | 517 | *gnssId = 1; |
165 | 517 | *svId = PRN; |
166 | 3.28k | } else if ((201 <= PRN) && |
167 | 1.82k | (239 >= PRN)) { |
168 | | // BeiDou |
169 | 629 | *gnssId = 3; |
170 | 629 | *svId = PRN - 200; |
171 | 2.65k | } else if ((240 <= PRN) && |
172 | 1.19k | (254 >= PRN)) { |
173 | | // IRNSS |
174 | 566 | *gnssId = 20; |
175 | 566 | *svId = PRN - 240; |
176 | 2.08k | } else { |
177 | | // huh? |
178 | 2.08k | *gnssId = 0; |
179 | 2.08k | *svId = 0; |
180 | 2.08k | } |
181 | 6.25k | return; |
182 | 6.25k | } |
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 | 640 | { |
192 | 640 | unsigned sid; |
193 | 640 | unsigned u[23]; |
194 | 640 | int i; |
195 | | |
196 | 640 | if (3 > len) { |
197 | 163 | GPSD_LOG(LOG_WARN, &session->context->errout, |
198 | 163 | "Skytraq 0x62: bad len %zu\n", len); |
199 | 163 | return 0; |
200 | 163 | } |
201 | | |
202 | 477 | sid = getub(buf, 1); |
203 | 477 | switch (sid) { |
204 | 104 | case 0x80: |
205 | | // SBAS status |
206 | 104 | if (8 < len) { |
207 | 69 | GPSD_LOG(LOG_WARN, &session->context->errout, |
208 | 69 | "Skytraq 0x62/80: bad len %zu\n", len); |
209 | 69 | return 0; |
210 | 69 | } |
211 | 245 | for (i = 0; i < 6; i++) { |
212 | 210 | u[i] = getub(buf, i + 2); |
213 | 210 | } |
214 | 35 | GPSD_LOG(LOG_PROG, &session->context->errout, |
215 | 35 | "Skytraq 0x62/80: enable %u ranging %u URA mask %u " |
216 | 35 | "correction %u chans %u subsystems %u \n", |
217 | 35 | u[0], u[1], u[2], u[3], u[4], u[5]); |
218 | 35 | break; |
219 | 68 | case 0x81: |
220 | | // QXSS status |
221 | 68 | u[0] = getub(buf, 2); |
222 | 68 | u[1] = getub(buf, 3); |
223 | 68 | GPSD_LOG(LOG_PROG, &session->context->errout, |
224 | 68 | "Skytraq 0x62/81: enable %u chans %u\n", |
225 | 68 | u[0], u[1]); |
226 | 68 | break; |
227 | 149 | case 0x82: |
228 | | // SBAS advanced status |
229 | 149 | if (46 < len) { |
230 | 71 | GPSD_LOG(LOG_WARN, &session->context->errout, |
231 | 71 | "Skytraq 0x62/82: bad len %zu\n", len); |
232 | 71 | return 0; |
233 | 71 | } |
234 | 1.79k | for (i = 0; i < 22; i++) { |
235 | 1.71k | u[i] = getub(buf, i + 2); |
236 | 1.71k | } |
237 | 78 | GPSD_LOG(LOG_PROG, &session->context->errout, |
238 | 78 | "Skytraq 0x62/82: enable %u ranging %u URA %u corr %u " |
239 | 78 | "chans %u mask x%02x WAAS %u %u %u %u " |
240 | 78 | "EGNOS %u %u %u %u MSAS %u %u %u %u " |
241 | 78 | "GAGAN %u %u %u %u\n", |
242 | 78 | u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], |
243 | 78 | u[9], u[10], u[11], u[12], u[13], u[14], u[15], u[16], u[17], |
244 | 78 | u[18], u[19], u[20], u[21]); |
245 | 78 | break; |
246 | 156 | default: |
247 | 156 | GPSD_LOG(LOG_PROG, &session->context->errout, |
248 | 477 | "Skytraq 0x62: SID x%02x len %zu\n", sid, len); |
249 | 477 | } |
250 | 337 | return 0; |
251 | 477 | } |
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 | 503 | { |
261 | 503 | unsigned sid; |
262 | | |
263 | 503 | if (3 > len) { |
264 | 382 | GPSD_LOG(LOG_WARN, &session->context->errout, |
265 | 382 | "Skytraq 0x63: bad len %zu\n", len); |
266 | 382 | return 0; |
267 | 382 | } |
268 | | |
269 | 121 | sid = getub(buf, 1); |
270 | | |
271 | | // FIXME: decode them! |
272 | 121 | GPSD_LOG(LOG_PROG, &session->context->errout, |
273 | 121 | "Skytraq 0x63: SID %u\n", sid); |
274 | 121 | return 0; |
275 | 503 | } |
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.02k | { |
285 | 1.02k | unsigned sid; |
286 | 1.02k | unsigned u[13]; |
287 | 1.02k | int i; |
288 | 1.02k | int s[3]; |
289 | | |
290 | 1.02k | if (3 > len) { |
291 | 39 | GPSD_LOG(LOG_WARN, &session->context->errout, |
292 | 39 | "Skytraq 0x64: bad len %zu\n", len); |
293 | 39 | return 0; |
294 | 39 | } |
295 | | |
296 | 984 | sid = getub(buf, 1); |
297 | 984 | switch (sid) { |
298 | 69 | case 0x80: |
299 | | // GNSS Boot status |
300 | 69 | u[0] = getub(buf, 2); |
301 | 69 | u[1] = getub(buf, 3); |
302 | 69 | GPSD_LOG(LOG_PROG, &session->context->errout, |
303 | 69 | "Skytraq 0x64/80: enable %u type %u\n", |
304 | 69 | u[0], u[1]); |
305 | 69 | break; |
306 | 105 | case 0x81: |
307 | | // Extended NMEA Message Interval |
308 | 105 | if (14 > len) { |
309 | 40 | GPSD_LOG(LOG_WARN, &session->context->errout, |
310 | 40 | "Skytraq 0x64/81: bad len %zu\n", len); |
311 | 40 | return 0; |
312 | 40 | } |
313 | 845 | for (i = 0; i < 12; i++) { |
314 | 780 | u[i] = getub(buf, i + 2); |
315 | 780 | } |
316 | 65 | GPSD_LOG(LOG_PROG, &session->context->errout, |
317 | 65 | "Skytraq 0x64/81: GGA %u GSA %u GSV %u GLL %u RMC %u " |
318 | 65 | "VTG %u ZDA %u GNS %u GBS %u GRS %u DTM %u GST %u\n", |
319 | 65 | u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], |
320 | 65 | u[9], u[10], u[11]); |
321 | 65 | break; |
322 | 51 | case 0x83: |
323 | | // Interference Detection Status |
324 | 51 | u[0] = getub(buf, 2); |
325 | 51 | u[1] = getub(buf, 3); |
326 | 51 | GPSD_LOG(LOG_PROG, &session->context->errout, |
327 | 51 | "Skytraq 0x64/83: enable %u status %u\n", |
328 | 51 | u[0], u[1]); |
329 | 51 | break; |
330 | 69 | case 0x85: |
331 | | // GPS PARAMETER SEARCH ENGINE NUMBER |
332 | 69 | u[0] = getub(buf, 2); |
333 | 69 | GPSD_LOG(LOG_PROG, &session->context->errout, |
334 | 69 | "Skytraq 0x64/85: search engine number %u\n", u[0]); |
335 | 69 | break; |
336 | 123 | case 0x88: |
337 | | // Position/Fix navigation mask |
338 | 123 | u[0] = getub(buf, 2); |
339 | 123 | u[1] = getub(buf, 3); |
340 | 123 | GPSD_LOG(LOG_PROG, &session->context->errout, |
341 | 123 | "Skytraq 0x64/88: 1st %u subsequent %u\n", |
342 | 123 | u[0], u[1]); |
343 | 123 | break; |
344 | 71 | case 0x8a: |
345 | | // GPS UTC Reference time |
346 | 71 | if (7 > len) { |
347 | 1 | GPSD_LOG(LOG_WARN, &session->context->errout, |
348 | 1 | "Skytraq 0x64/8a: bad len %zu\n", len); |
349 | 1 | return 0; |
350 | 1 | } |
351 | 70 | u[0] = getub(buf, 2); |
352 | 70 | u[1] = getbeu16(buf, 3); |
353 | 70 | u[2] = getub(buf, 5); |
354 | 70 | u[3] = getub(buf, 6); |
355 | 70 | GPSD_LOG(LOG_PROG, &session->context->errout, |
356 | 70 | "Skytraq 0x64/8a: enable %u year %u month %u day %u\n", |
357 | 70 | u[0], u[1], u[2], u[3]); |
358 | 70 | break; |
359 | 76 | case 0x8b: |
360 | | // GNSS Nav mode |
361 | 76 | u[0] = getub(buf, 2); |
362 | 76 | GPSD_LOG(LOG_PROG, &session->context->errout, |
363 | 76 | "Skytraq 0x64/8b: mode %u\n", u[0]); |
364 | 76 | break; |
365 | 76 | case 0x8c: |
366 | | // GNSS Constellation type for nav solution |
367 | 76 | u[0] = getbeu16(buf, 2); |
368 | 76 | GPSD_LOG(LOG_PROG, &session->context->errout, |
369 | 76 | "Skytraq 0x64/8c: Nav Type x%02x\n", u[0]); |
370 | 76 | break; |
371 | 67 | case 0x8e: |
372 | | // GPS time |
373 | 67 | u[0] = getbeu32(buf, 2); // TOW ms |
374 | 67 | u[1] = getbeu32(buf, 6); // TOW ns |
375 | 67 | u[2] = getbeu16(buf, 10); // GPS week |
376 | 67 | s[0] = getsb(buf, 12); // default leap s |
377 | 67 | s[1] = getsb(buf, 13); // current leap s |
378 | 67 | u[3] = getub(buf, 14); // valid |
379 | | // FIXME: save GPS week and leap s |
380 | 67 | GPSD_LOG(LOG_PROG, &session->context->errout, |
381 | 67 | "Skytraq 0x64/8a: TOW %u %u week %u leap %d %d valid x%x\n", |
382 | 67 | u[0], u[1], u[2], s[0], s[1], u[3]); |
383 | 67 | break; |
384 | 36 | case 0x92: |
385 | | // GLONASS Time corrections |
386 | 36 | s[0] = getbes32(buf, 2); // tau c |
387 | 36 | s[1] = getbes32(buf, 6); // tau gps |
388 | 36 | GPSD_LOG(LOG_PROG, &session->context->errout, |
389 | 36 | "Skytraq 0x64/92: tau c %d tau GPS %d\n", |
390 | 36 | s[0], s[1]); |
391 | 36 | 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 | 174 | default: |
398 | 174 | GPSD_LOG(LOG_PROG, &session->context->errout, |
399 | 984 | "Skytraq 0x64: SID x%02x len %zu\n", sid, len); |
400 | 984 | } |
401 | 943 | 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 | 505 | { |
412 | 505 | unsigned sid; |
413 | 505 | unsigned u[13]; |
414 | | |
415 | 505 | if (3 > len) { |
416 | 219 | GPSD_LOG(LOG_WARN, &session->context->errout, |
417 | 219 | "Skytraq 0x65: bad len %zu\n", len); |
418 | 219 | return 0; |
419 | 219 | } |
420 | | |
421 | 286 | sid = getub(buf, 1); |
422 | 286 | switch (sid) { |
423 | 69 | case 0x80: |
424 | | // 1PPS Pulse width |
425 | 69 | u[0] = getbeu32(buf, 2); // pulse width miicro seconds |
426 | 69 | GPSD_LOG(LOG_PROG, &session->context->errout, |
427 | 69 | "Skytraq 0x65/80: width %u\n", u[0]); |
428 | 69 | break; |
429 | 72 | case 0x81: |
430 | | // PPS2 frequency |
431 | 72 | u[0] = getbeu32(buf, 2); // freq of PPS2 Hz |
432 | 72 | GPSD_LOG(LOG_PROG, &session->context->errout, |
433 | 72 | "Skytraq 0x65/81: PPS2 Hz %u\n", u[0]); |
434 | 72 | break; |
435 | 145 | default: |
436 | 145 | GPSD_LOG(LOG_PROG, &session->context->errout, |
437 | 286 | "Skytraq 0x65: SID x%02x len %zu\n", sid, len); |
438 | 286 | } |
439 | 286 | return 0; |
440 | 286 | } |
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 | 744 | { |
450 | 744 | unsigned sid; |
451 | 744 | unsigned u[13]; |
452 | 744 | double d[5]; |
453 | | |
454 | 744 | if (3 > len) { |
455 | 259 | GPSD_LOG(LOG_WARN, &session->context->errout, |
456 | 259 | "Skytraq 0x6A: bad len %zu\n", len); |
457 | 259 | return 0; |
458 | 259 | } |
459 | | |
460 | 485 | sid = getub(buf, 1); |
461 | 485 | switch (sid) { |
462 | 115 | case 0x83: |
463 | | // RTK mode and operational functioN |
464 | 115 | u[0] = getub(buf, 2); // RTK mode |
465 | 115 | u[1] = getub(buf, 3); // RTK function |
466 | 115 | u[2] = getbeu32(buf, 4); // saved survey length |
467 | 115 | u[3] = getbeu32(buf, 8); // standard deviation |
468 | 115 | d[0] = getled64((const char *)buf, 12); // latitude |
469 | 115 | d[1] = getled64((const char *)buf, 20); // longitude |
470 | 115 | d[3] = getlef32((const char *)buf, 28); // altitude (HAE or MSL?) |
471 | 115 | u[4] = getub(buf, 32); // runtime function |
472 | 115 | u[5] = getbeu32(buf, 33); // run-time survey length |
473 | 115 | d[4] = getlef32((const char *)buf, 37); // baseline length constant |
474 | 115 | GPSD_LOG(LOG_PROG, &session->context->errout, |
475 | 115 | "Skytraq 0x6A/83: mode %u func %u len %u sdev %u lat %.8f " |
476 | 115 | "lon %.8f alt %.4f func %u len %u len %.4f\n", |
477 | 115 | u[0], u[1], u[2], u[3], d[0], d[1], d[3], u[4], u[5], d[4]); |
478 | 115 | break; |
479 | 150 | case 0x85: |
480 | | // RTK slave base serial port baud ratE |
481 | 150 | u[0] = getub(buf, 2); // rate code |
482 | 150 | GPSD_LOG(LOG_PROG, &session->context->errout, |
483 | 150 | "Skytraq 0x6A/85: rate %u\n", u[0]); |
484 | 150 | break; |
485 | 101 | case 0x88: |
486 | | // RTK kinematic base serial port baud ratE |
487 | 101 | u[0] = getub(buf, 2); // rate code |
488 | 101 | GPSD_LOG(LOG_PROG, &session->context->errout, |
489 | 101 | "Skytraq 0x6A/88: rate %u\n", u[0]); |
490 | 101 | break; |
491 | 119 | default: |
492 | 119 | GPSD_LOG(LOG_PROG, &session->context->errout, |
493 | 485 | "Skytraq 0x6A: SID x%02x len %zu\n", sid, len); |
494 | 485 | } |
495 | 485 | return 0; |
496 | 485 | } |
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 | 253 | { |
506 | 253 | unsigned sid, ssid; |
507 | 253 | unsigned u[16]; |
508 | 253 | double d[2]; |
509 | 253 | int i; |
510 | | |
511 | 253 | if (3 > len) { |
512 | 149 | GPSD_LOG(LOG_WARN, &session->context->errout, |
513 | 149 | "Skytraq 0x7A: bad len %zu\n", len); |
514 | 149 | return 0; |
515 | 149 | } |
516 | | |
517 | 104 | sid = getub(buf, 1); |
518 | 104 | ssid = getub(buf, 2); |
519 | 104 | 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 | 99 | default: |
560 | 99 | GPSD_LOG(LOG_PROG, &session->context->errout, |
561 | 104 | "Skytraq 0x7A: SID x%02x/%02x len %zu\n", sid, ssid, len); |
562 | 104 | } |
563 | 103 | return 0; |
564 | 104 | } |
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 | 254 | { |
578 | 254 | unsigned kver_x; // kernel version |
579 | 254 | unsigned kver_y; // kernel version |
580 | 254 | unsigned kver_z; // kernel version |
581 | 254 | unsigned over_x; // ODM version |
582 | 254 | unsigned over_y; // ODM version |
583 | 254 | unsigned over_z; // ODM version |
584 | 254 | unsigned rev_yy; // revision |
585 | 254 | unsigned rev_mm; // revision |
586 | 254 | unsigned rev_dd; // revision |
587 | | |
588 | 254 | if (14 != len) { |
589 | 188 | return 0; |
590 | 188 | } |
591 | | |
592 | 66 | kver_x = getbeu16(buf, 2); |
593 | 66 | kver_y = getub(buf, 4); |
594 | 66 | kver_z = getub(buf, 5); |
595 | 66 | over_x = getbeu16(buf, 6); |
596 | 66 | over_y = getub(buf, 8); |
597 | 66 | over_z = getub(buf, 9); |
598 | 66 | rev_yy = getbeu16(buf, 10); |
599 | 66 | rev_mm = getub(buf, 12); |
600 | 66 | rev_dd = getub(buf, 13); |
601 | | |
602 | 66 | (void)snprintf(session->subtype, sizeof(session->subtype) - 1, |
603 | 66 | "kver %u.%u.%u over %u.%u.%u rev %02u.%02u.%02u", |
604 | 66 | kver_x, kver_y, kver_z, |
605 | 66 | over_x, over_y, over_z, |
606 | 66 | rev_yy, rev_mm, rev_dd); |
607 | | |
608 | 66 | GPSD_LOG(LOG_PROG, &session->context->errout, |
609 | 66 | "Skytraq 0x80: %s\n", |
610 | 66 | session->subtype); |
611 | 66 | return 0; |
612 | 254 | } |
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 | 94 | { |
622 | 94 | unsigned type, crc; |
623 | | |
624 | 94 | if (4 != len) { |
625 | 70 | GPSD_LOG(LOG_WARN, &session->context->errout, |
626 | 70 | "Skytraq 0x81: bad len %zu\n", len); |
627 | 70 | return 0; |
628 | 70 | } |
629 | | |
630 | 24 | type = getub(buf, 1); |
631 | 24 | crc = getbeu16(buf, 2); |
632 | | |
633 | 24 | GPSD_LOG(LOG_PROG, &session->context->errout, |
634 | 24 | "Skytraq 0x81: type %u crc %u\n", type, crc); |
635 | 24 | return 0; |
636 | 94 | } |
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 | 146 | { |
646 | 146 | unsigned rate; |
647 | | |
648 | 146 | 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 | 76 | rate = getub(buf, 1); |
655 | | |
656 | 76 | GPSD_LOG(LOG_PROG, &session->context->errout, |
657 | 76 | "Skytraq 0x86: rate %u\n", rate); |
658 | 76 | return 0; |
659 | 146 | } |
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 | 168 | { |
669 | 168 | unsigned i; |
670 | 168 | uint8_t u[7]; |
671 | | |
672 | 168 | if (8 != len) { |
673 | 92 | GPSD_LOG(LOG_WARN, &session->context->errout, |
674 | 92 | "Skytraq 0x89: bad len %zu\n", len); |
675 | 92 | return 0; |
676 | 92 | } |
677 | | |
678 | 608 | for (i = 0; i < 7; i++) { |
679 | 532 | u[i] = getub(buf, i + 1); |
680 | 532 | } |
681 | 76 | GPSD_LOG(LOG_PROG, &session->context->errout, |
682 | 76 | "Skytraq 0x89: rate %u Meas %u raw %u CH_status %u " |
683 | 76 | "RCV_statas %u subf %u eraw %u\n", |
684 | 76 | u[0], u[1], u[2], u[3], u[4], u[5], u[6]); |
685 | | |
686 | 76 | return 0; |
687 | 168 | } |
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 | 645 | { |
697 | 645 | unsigned i; |
698 | 645 | uint8_t u[15]; |
699 | | |
700 | 645 | if (16 != len) { |
701 | 644 | GPSD_LOG(LOG_WARN, &session->context->errout, |
702 | 644 | "Skytraq 0x8A: bad len %zu\n", len); |
703 | 644 | return 0; |
704 | 644 | } |
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 | 645 | } |
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 | 181 | { |
727 | 181 | uint8_t u[5]; |
728 | 181 | double d[3]; |
729 | | |
730 | 181 | if (35 != len) { |
731 | 138 | GPSD_LOG(LOG_WARN, &session->context->errout, |
732 | 138 | "Skytraq 0x8B: bad len %zu\n", len); |
733 | 138 | return 0; |
734 | 138 | } |
735 | | |
736 | 43 | u[0] = getub(buf, 1); |
737 | 43 | u[1] = getbeu32(buf, 2); |
738 | 43 | u[2] = getbeu32(buf, 6); |
739 | 43 | d[0] = getbed64((const char *)buf, 10); |
740 | 43 | d[1] = getbed64((const char *)buf, 18); |
741 | 43 | d[2] = getbef32((const char *)buf, 26); |
742 | 43 | u[3] = getub(buf, 30); |
743 | 43 | u[4] = getbeu32(buf, 31); |
744 | | |
745 | 43 | GPSD_LOG(LOG_PROG, &session->context->errout, |
746 | 43 | "Skytraq 0x8B: saved mode %u saved length %u stddev %u " |
747 | 43 | "lat %.9f lon %.9f HAE %0.4f run mode %u survey len %u\n", |
748 | 43 | u[0], u[1], u[2], d[0], d[1], d[2], u[3], u[4]); |
749 | | |
750 | 43 | return 0; |
751 | 181 | } |
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 | 362 | { |
761 | 362 | unsigned mode; |
762 | | |
763 | 362 | if (2 != len) { |
764 | 90 | GPSD_LOG(LOG_WARN, &session->context->errout, |
765 | 90 | "Skytraq 0x93: bad len %zu\n", len); |
766 | 90 | return 0; |
767 | 90 | } |
768 | | |
769 | 272 | mode = getub(buf, 1); |
770 | | |
771 | 272 | GPSD_LOG(LOG_PROG, &session->context->errout, |
772 | 272 | "Skytraq 0x93: mode %u\n", mode); |
773 | 272 | return 0; |
774 | 362 | } |
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 | 131 | { |
792 | 131 | unsigned char navmode; // Navigation fix mode (0: No fix, 1: 2D, 2: 3D, 3: 3D+DGNSS |
793 | 131 | unsigned short week; // GNSS week number |
794 | 131 | double ftow; // Time of week |
795 | 131 | timespec_t ts_tow; |
796 | 131 | char ts_buf[TIMESPEC_LEN]; |
797 | | |
798 | 131 | int *mode = &session->newdata.mode; |
799 | 131 | int *status = &session->newdata.status; |
800 | 131 | gps_mask_t mask = 0; |
801 | | |
802 | 131 | if (59 != len) { |
803 | 123 | GPSD_LOG(LOG_INF, &session->context->errout, "Skytraq: " |
804 | 123 | "Navigation Data Message has incorrect length %zu\n", len); |
805 | 123 | return 0; |
806 | 123 | } |
807 | | |
808 | 8 | navmode = getub(buf, 1); |
809 | 8 | switch (navmode) { |
810 | 1 | case 1: // 2D fix |
811 | 1 | *mode = MODE_2D; |
812 | 1 | *status = STATUS_GPS; |
813 | 1 | break; |
814 | 4 | case 2: // 3D fix |
815 | 4 | *mode = MODE_3D; |
816 | 4 | *status = STATUS_GPS; |
817 | 4 | break; |
818 | 1 | case 3: // 3D DGPS fix |
819 | 1 | *mode = MODE_3D; |
820 | 1 | *status = STATUS_DGPS; |
821 | 1 | break; |
822 | | |
823 | 2 | default: // Includes SKY_MODE_NONE |
824 | 2 | *mode = MODE_NO_FIX; |
825 | 2 | *status = STATUS_UNK; |
826 | 2 | break; |
827 | 8 | } |
828 | 8 | mask |= MODE_SET | STATUS_SET; |
829 | | |
830 | 8 | session->gpsdata.satellites_used = getub(buf, 2); |
831 | | |
832 | 8 | mask |= ONLINE_SET; |
833 | 8 | week = getbeu16(buf, 3); |
834 | 8 | ftow = getbeu32(buf, 5) / 100.0; |
835 | 8 | DTOTS(&ts_tow, (int)ftow); |
836 | | |
837 | 8 | session->newdata.time = gpsd_gpstime_resolv(session, week, ts_tow); |
838 | 8 | mask |= TIME_SET; |
839 | | |
840 | 8 | if (MODE_2D == *mode || MODE_3D == *mode) { |
841 | 6 | session->newdata.latitude = getbes32(buf, 9) / 1e7; |
842 | 6 | session->newdata.longitude = getbes32(buf, 13) / 1e7; |
843 | 6 | mask |= LATLON_SET | NTPTIME_IS; |
844 | | |
845 | 6 | if (MODE_3D == *mode) { |
846 | 5 | session->newdata.altHAE = getbes32(buf, 17) / 100.0; |
847 | 5 | session->newdata.altMSL = getbes32(buf, 21) / 100.0; |
848 | | |
849 | 5 | session->newdata.ecef.x = getbes32(buf, 35) / 100.0; |
850 | 5 | session->newdata.ecef.y = getbes32(buf, 39) / 100.0; |
851 | 5 | session->newdata.ecef.z = getbes32(buf, 43) / 100.0; |
852 | 5 | session->newdata.ecef.vx = getbes32(buf, 47) / 100.0; |
853 | 5 | session->newdata.ecef.vy = getbes32(buf, 51) / 100.0; |
854 | 5 | session->newdata.ecef.vz = getbes32(buf, 55) / 100.0; |
855 | 5 | mask |= ECEF_SET | VECEF_SET | ALTITUDE_SET; |
856 | 5 | } |
857 | 6 | } |
858 | | |
859 | 8 | session->gpsdata.dop.gdop = getbeu16(buf, 25) / 100.0; |
860 | 8 | session->gpsdata.dop.pdop = getbeu16(buf, 27) / 100.0; |
861 | 8 | session->gpsdata.dop.hdop = getbeu16(buf, 29) / 100.0; |
862 | 8 | session->gpsdata.dop.vdop = getbeu16(buf, 31) / 100.0; |
863 | 8 | session->gpsdata.dop.tdop = getbeu16(buf, 33) / 100.0; |
864 | 8 | mask |= DOP_SET | CLEAR_IS | REPORT_IS; |
865 | 8 | GPSD_LOG(LOG_DATA, &session->context->errout, |
866 | 8 | "Skytraq: NAVDATA time=%s, lat=%.7f lon=%.7f altHAE=%.2f altMSL=%.2f mode=%d status=%d " |
867 | 8 | "gdop: %.2f, hdop: %.2f, pdop: %.2f, tdop: %.2f, vdop: %.2f\n", |
868 | 8 | timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)), |
869 | 8 | session->newdata.latitude, |
870 | 8 | session->newdata.longitude, |
871 | 8 | session->newdata.altHAE, |
872 | 8 | session->newdata.altMSL, |
873 | 8 | session->newdata.mode, |
874 | 8 | session->newdata.status, |
875 | 8 | session->gpsdata.dop.gdop, |
876 | 8 | session->gpsdata.dop.hdop, |
877 | 8 | session->gpsdata.dop.pdop, |
878 | 8 | session->gpsdata.dop.tdop, |
879 | 8 | session->gpsdata.dop.vdop); |
880 | 8 | return mask; |
881 | 8 | } |
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.94k | { |
891 | 1.94k | unsigned datum; |
892 | | |
893 | 1.94k | if (3 != len) { |
894 | 1.65k | GPSD_LOG(LOG_WARN, &session->context->errout, |
895 | 1.65k | "Skytraq 0xAE: bad len %zu\n", len); |
896 | 1.65k | return 0; |
897 | 1.65k | } |
898 | | |
899 | 284 | datum = getbeu16(buf, 1); |
900 | | |
901 | 284 | GPSD_LOG(LOG_PROG, &session->context->errout, |
902 | 284 | "Skytraq 0xAE: datum %u\n", datum); |
903 | 284 | return 0; |
904 | 1.94k | } |
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 | 142 | { |
914 | 142 | unsigned mode, pdop, hdop, gdop; |
915 | | |
916 | 142 | if (8 != len) { |
917 | 141 | GPSD_LOG(LOG_WARN, &session->context->errout, |
918 | 141 | "Skytraq 0xAF: bad len %zu\n", len); |
919 | 141 | return 0; |
920 | 141 | } |
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 | 142 | } |
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 | 167 | { |
941 | 167 | unsigned select, elevation, cnr; |
942 | | |
943 | 167 | if (4 != len) { |
944 | 166 | GPSD_LOG(LOG_WARN, &session->context->errout, |
945 | 166 | "Skytraq 0xB0: bad len %zu\n", len); |
946 | 166 | return 0; |
947 | 166 | } |
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 | 167 | } |
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 | 133 | { |
967 | 133 | unsigned status, pspeed, pcnt, uspeed, ucnt, udist; |
968 | | |
969 | 133 | if (12 != len) { |
970 | 132 | GPSD_LOG(LOG_WARN, &session->context->errout, |
971 | 132 | "Skytraq 0xB4: bad len %zu\n", len); |
972 | 132 | return 0; |
973 | 132 | } |
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 | 133 | } |
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 | 296 | { |
997 | 296 | unsigned mode; |
998 | | |
999 | 296 | if (2 != len) { |
1000 | 206 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1001 | 206 | "Skytraq 0xB9: bad len %zu\n", len); |
1002 | 206 | return 0; |
1003 | 206 | } |
1004 | | |
1005 | 90 | mode = getub(buf, 1); |
1006 | | |
1007 | 90 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1008 | 90 | "Skytraq 0xB9: mode %u\n", mode); |
1009 | 90 | return 0; |
1010 | 296 | } |
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 | 68 | { |
1020 | 68 | int delay; |
1021 | | |
1022 | 68 | if (5 != len) { |
1023 | 67 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1024 | 67 | "Skytraq 0xBB: bad len %zu\n", len); |
1025 | 67 | return 0; |
1026 | 67 | } |
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 | 68 | } |
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 | 453 | { |
1043 | 453 | unsigned iod; // Issue of data 0 - 255 |
1044 | 453 | unsigned wn; // week number 0 - 65535 |
1045 | 453 | unsigned tow; // receiver tow 0 - 604799999 in mS |
1046 | 453 | unsigned mp; // measurement period 1 - 1000 ms |
1047 | 453 | char ts_buf[TIMESPEC_LEN]; |
1048 | 453 | timespec_t ts_tow; |
1049 | | |
1050 | 453 | if (10 != len) { |
1051 | 385 | return 0; |
1052 | 385 | } |
1053 | | |
1054 | 68 | iod = (unsigned)getub(buf, 1); |
1055 | 68 | wn = getbeu16(buf, 2); |
1056 | 68 | tow = getbeu32(buf, 4); |
1057 | 68 | mp = getbeu16(buf, 8); |
1058 | 68 | MSTOTS(&ts_tow, tow); |
1059 | | |
1060 | | // should this be newdata.skyview_time? |
1061 | 68 | session->gpsdata.skyview_time = gpsd_gpstime_resolv(session, wn, ts_tow); |
1062 | | |
1063 | 68 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1064 | 68 | "Skytraq 0xDC: iod %u wn %u tow %u mp %u t%s\n", |
1065 | 68 | iod, wn, tow, mp, |
1066 | 68 | timespec_str(&session->gpsdata.skyview_time, ts_buf, |
1067 | 68 | sizeof(ts_buf))); |
1068 | 68 | return 0; |
1069 | 453 | } |
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 | 966 | { |
1078 | 966 | unsigned i; // generic loop variable |
1079 | | |
1080 | | // buf[0] os the message ID |
1081 | | // Issue of data 0 - 255 |
1082 | 966 | unsigned iod = (unsigned)getub(buf, 1); |
1083 | | // number of measurements |
1084 | 966 | unsigned nmeas = (unsigned)getub(buf, 2); |
1085 | | |
1086 | 966 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1087 | 966 | "Skytraq 0xDD: iod %u, nmeas %u len %zd\n", |
1088 | 966 | iod, nmeas, len); |
1089 | | |
1090 | 966 | if (len < (3 + (nmeas * 23))) { |
1091 | 192 | GPSD_LOG(LOG_ERROR, &session->context->errout, |
1092 | 192 | "Skytraq 0xDD: bad len %zd, s/b %d\n", |
1093 | 192 | len, 3 + (nmeas & 23)); |
1094 | 192 | return 0; |
1095 | 192 | } |
1096 | | |
1097 | | // check IOD? |
1098 | 774 | 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 | 774 | memset(session->gpsdata.raw.meas, 0, sizeof(session->gpsdata.raw.meas)); |
1103 | | |
1104 | 4.16k | for (i = 0; i < nmeas; i++) { |
1105 | 3.39k | const char *obs_code; |
1106 | 3.39k | int off = 3 + (23 * i); |
1107 | | |
1108 | 3.39k | uint8_t PRN = getub(buf, off + 0); |
1109 | | // carrier-to-noise density ratio dB-Hz |
1110 | 3.39k | uint8_t cno = getub(buf, off + 1); |
1111 | | // pseudorange in meters |
1112 | 3.39k | double prMes = getbed64((const char *)buf, off + 2); |
1113 | | // carrier phase in cycles |
1114 | 3.39k | double cpMes = getbed64((const char *)buf, off + 10); |
1115 | | // doppler in Hz, positive towards sat |
1116 | 3.39k | 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 | 3.39k | uint8_t trkStat = getub(buf, off + 22); |
1126 | 3.39k | uint8_t gnssId = 0; |
1127 | | // svId should always be from 0 to 99, except SBAS. |
1128 | 3.39k | uint8_t svId = 0; |
1129 | 3.39k | PRN2_gnssId_svId(PRN, &gnssId, &svId); |
1130 | | |
1131 | 3.39k | session->gpsdata.raw.meas[i].gnssid = gnssId; |
1132 | 3.39k | switch (gnssId) { |
1133 | 1.95k | case 0: // GPS |
1134 | 1.95k | FALLTHROUGH |
1135 | 1.95k | case 5: // QZSS |
1136 | 1.95k | FALLTHROUGH |
1137 | 2.13k | case 20: // IRNSS, just guessing here |
1138 | 2.13k | obs_code = "L1C"; // u-blox calls this L1C/A ? |
1139 | 2.13k | break; |
1140 | 280 | case 1: // SBAS |
1141 | 280 | if (100 < svId) { |
1142 | | // Should be always true, but pacify Coverity 498045 |
1143 | 280 | svId -= 100; // adjust for RINEX 3 svid |
1144 | 280 | } |
1145 | 280 | obs_code = "L1C"; // u-blox calls this L1C/A |
1146 | 280 | break; |
1147 | 0 | case 2: // GALILEO |
1148 | 0 | obs_code = "L1B"; // u-blox calls this E1OS |
1149 | 0 | break; |
1150 | 339 | case 3: // BeiDou |
1151 | 339 | obs_code = "L2I"; // u-blox calls this B1I |
1152 | 339 | 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 | 639 | case 6: // GLONASS |
1159 | 639 | obs_code = "L1C"; // u-blox calls this L1OF |
1160 | 639 | break; |
1161 | 3.39k | } |
1162 | 3.39k | (void)strlcpy(session->gpsdata.raw.meas[i].obs_code, obs_code, |
1163 | 3.39k | sizeof(session->gpsdata.raw.meas[i].obs_code)); |
1164 | | |
1165 | 3.39k | session->gpsdata.raw.meas[i].svid = svId; |
1166 | 3.39k | session->gpsdata.raw.meas[i].snr = cno; |
1167 | 3.39k | session->gpsdata.raw.meas[i].satstat = trkStat; |
1168 | 3.39k | if (trkStat & 1) { |
1169 | | // prMes valid |
1170 | 1.71k | session->gpsdata.raw.meas[i].pseudorange = prMes; |
1171 | 1.71k | } else { |
1172 | 1.67k | session->gpsdata.raw.meas[i].pseudorange = NAN; |
1173 | 1.67k | } |
1174 | 3.39k | if (trkStat & 2) { |
1175 | | // doppler valid |
1176 | 1.83k | session->gpsdata.raw.meas[i].doppler = doMes; |
1177 | 1.83k | } else { |
1178 | 1.56k | session->gpsdata.raw.meas[i].doppler = NAN; |
1179 | 1.56k | } |
1180 | 3.39k | if (trkStat & 4) { |
1181 | | // cpMes valid |
1182 | 1.50k | session->gpsdata.raw.meas[i].carrierphase = cpMes; |
1183 | 1.88k | } else { |
1184 | 1.88k | session->gpsdata.raw.meas[i].carrierphase = NAN; |
1185 | 1.88k | } |
1186 | 3.39k | session->gpsdata.raw.meas[i].codephase = NAN; |
1187 | 3.39k | session->gpsdata.raw.meas[i].deltarange = NAN; |
1188 | | // skytraq does not report locktime, so assume max |
1189 | 3.39k | session->gpsdata.raw.meas[i].locktime = LOCKMAX; |
1190 | 3.39k | if (trkStat & 8) { |
1191 | | // possible slip |
1192 | 1.48k | session->gpsdata.raw.meas[i].lli = 2; |
1193 | 1.48k | } |
1194 | 3.39k | GPSD_LOG(LOG_DATA, &session->context->errout, |
1195 | 3.39k | "PRN %u (%u:%u) prMes %f cpMes %f doMes %f\n" |
1196 | 3.39k | "cno %u rtkStat %u\n", PRN, |
1197 | 3.39k | gnssId, svId, prMes, cpMes, doMes, cno, trkStat); |
1198 | | |
1199 | 3.39k | } |
1200 | | |
1201 | | // return RAW_IS; // WIP |
1202 | 774 | return 0; |
1203 | 774 | } |
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.47k | { |
1213 | 1.47k | int st, nsv; |
1214 | 1.47k | unsigned i; |
1215 | 1.47k | unsigned iod; // Issue of data 0 - 255 |
1216 | 1.47k | unsigned nsvs; // number of SVs in this packet |
1217 | | |
1218 | 1.47k | if (3 > len) { |
1219 | 341 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1220 | 341 | "Skytraq 0xDE: bad len %zu\n", len); |
1221 | 341 | return 0; |
1222 | 341 | } |
1223 | 1.13k | iod = (unsigned)getub(buf, 1); |
1224 | 1.13k | nsvs = (unsigned)getub(buf, 2); |
1225 | | // too many sats? |
1226 | 1.13k | if (SKY_CHANNELS < nsvs) { |
1227 | 70 | return 0; |
1228 | 70 | } |
1229 | | |
1230 | 1.06k | if (len < (3 + (nsvs * 10))) { |
1231 | 115 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1232 | 115 | "Skytraq 0xDE: bad len %zu\n", len); |
1233 | 115 | return 0; |
1234 | 115 | } |
1235 | 948 | gpsd_zero_satellites(&session->gpsdata); |
1236 | 4.12k | for (i = st = nsv = 0; i < nsvs; i++) { |
1237 | 3.17k | int off = 3 + (10 * i); // offset into buffer of start of this sat |
1238 | 3.17k | bool good; // do we have a good record ? |
1239 | 3.17k | unsigned short sv_stat; |
1240 | 3.17k | unsigned short chan_stat; |
1241 | 3.17k | unsigned short ura; |
1242 | 3.17k | short PRN; |
1243 | 3.17k | uint8_t gnssId = 0; |
1244 | 3.17k | uint8_t svId = 0; |
1245 | | |
1246 | 3.17k | PRN = (short)getub(buf, off + 1); |
1247 | | // fit into gnssid:svid |
1248 | 3.17k | if (0 == PRN) { |
1249 | | // skip 0 PRN |
1250 | 305 | continue; |
1251 | 305 | } |
1252 | 2.86k | PRN2_gnssId_svId(PRN, &gnssId, &svId); |
1253 | | |
1254 | 2.86k | session->gpsdata.skyview[st].gnssid = gnssId; |
1255 | 2.86k | session->gpsdata.skyview[st].svid = svId; |
1256 | 2.86k | session->gpsdata.skyview[st].PRN = PRN; |
1257 | | |
1258 | 2.86k | sv_stat = (unsigned short)getub(buf, off + 2); |
1259 | 2.86k | ura = (unsigned short)getub(buf, off + 3); |
1260 | 2.86k | session->gpsdata.skyview[st].ss = (double)getub(buf, off + 4); |
1261 | 2.86k | session->gpsdata.skyview[st].elevation = |
1262 | 2.86k | (double)getbes16(buf, off + 5); |
1263 | 2.86k | session->gpsdata.skyview[st].azimuth = |
1264 | 2.86k | (double)getbes16(buf, off + 7); |
1265 | 2.86k | chan_stat = (unsigned short)getub(buf, off + 9); |
1266 | | |
1267 | 2.86k | session->gpsdata.skyview[st].used = (bool)(chan_stat & 0x30); |
1268 | 2.86k | good = session->gpsdata.skyview[st].PRN != 0 && |
1269 | 2.86k | session->gpsdata.skyview[st].azimuth != 0 && |
1270 | 2.59k | session->gpsdata.skyview[st].elevation != 0; |
1271 | | |
1272 | 2.86k | GPSD_LOG(LOG_DATA, &session->context->errout, |
1273 | 2.86k | "Skytraq PRN=%2d El=%4.0f Az=%5.0f ss=%3.2f stat=%02x,%02x " |
1274 | 2.86k | "ura=%d %c\n", |
1275 | 2.86k | session->gpsdata.skyview[st].PRN, |
1276 | 2.86k | session->gpsdata.skyview[st].elevation, |
1277 | 2.86k | session->gpsdata.skyview[st].azimuth, |
1278 | 2.86k | session->gpsdata.skyview[st].ss, |
1279 | 2.86k | chan_stat, sv_stat, ura, |
1280 | 2.86k | good ? '*' : ' '); |
1281 | | |
1282 | 2.86k | if (good) { |
1283 | 2.42k | st += 1; |
1284 | 2.42k | if (session->gpsdata.skyview[st].used) { |
1285 | 18 | nsv++; |
1286 | 18 | } |
1287 | 2.42k | } |
1288 | 2.86k | } |
1289 | | |
1290 | 948 | session->gpsdata.satellites_visible = st; |
1291 | 948 | if (MAXCHANNELS < session->gpsdata.satellites_visible) { |
1292 | 3 | GPSD_LOG(LOG_WARN, &session->context->errout, |
1293 | 3 | "Skytraq 0xDE: too many satellites %d\n", |
1294 | 3 | session->gpsdata.satellites_visible); |
1295 | 3 | session->gpsdata.satellites_visible = MAXCHANNELS; |
1296 | 3 | } |
1297 | 948 | session->gpsdata.satellites_used = nsv; |
1298 | | |
1299 | 948 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1300 | 948 | "Skytraq 0xDE: nsvs=%u visible=%u iod=%u\n", nsvs, |
1301 | 948 | session->gpsdata.satellites_visible, iod); |
1302 | 948 | return SATELLITE_SET | USED_IS; |
1303 | 1.06k | } |
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 | 76 | { |
1313 | 76 | unsigned short navstat; |
1314 | 76 | unsigned iod; // Issue of data 0 - 255 |
1315 | 76 | unsigned wn; // week number 0 - 65535 |
1316 | 76 | double f_tow; // receiver tow Sec |
1317 | 76 | double clock_bias; |
1318 | 76 | double clock_drift; |
1319 | 76 | gps_mask_t mask = 0; |
1320 | 76 | timespec_t ts_tow; |
1321 | 76 | char ts_buf[TIMESPEC_LEN]; |
1322 | | |
1323 | 76 | if (81 != len) { |
1324 | 74 | return 0; |
1325 | 74 | } |
1326 | | |
1327 | 2 | iod = (unsigned)getub(buf, 1); |
1328 | | |
1329 | | // fix status is byte 2 |
1330 | 2 | navstat = (unsigned short)getub(buf, 2); |
1331 | 2 | session->newdata.status = STATUS_UNK; |
1332 | 2 | session->newdata.mode = MODE_NO_FIX; |
1333 | 2 | switch (navstat) { |
1334 | 0 | case 1: |
1335 | | // fix prediction, ignore |
1336 | 0 | break; |
1337 | 1 | case 2: |
1338 | 1 | session->newdata.status = STATUS_GPS; |
1339 | 1 | session->newdata.mode = MODE_2D; |
1340 | 1 | break; |
1341 | 0 | case 3: |
1342 | 0 | session->newdata.status = STATUS_GPS; |
1343 | 0 | session->newdata.mode = MODE_3D; |
1344 | 0 | break; |
1345 | 0 | case 4: |
1346 | 0 | session->newdata.status = STATUS_DGPS; |
1347 | 0 | session->newdata.mode = MODE_3D; |
1348 | 0 | break; |
1349 | 1 | default: |
1350 | 1 | break; |
1351 | 2 | } |
1352 | | |
1353 | 2 | wn = getbeu16(buf, 3); |
1354 | 2 | f_tow = getbed64((const char *)buf, 5); |
1355 | 2 | DTOTS(&ts_tow, f_tow); |
1356 | | |
1357 | | // position/velocity is bytes 13-48, meters and m/s |
1358 | 2 | session->newdata.ecef.x = (double)getbed64((const char *)buf, 13), |
1359 | 2 | session->newdata.ecef.y = (double)getbed64((const char *)buf, 21), |
1360 | 2 | session->newdata.ecef.z = (double)getbed64((const char *)buf, 29), |
1361 | 2 | session->newdata.ecef.vx = (double)getbef32((const char *)buf, 37), |
1362 | 2 | session->newdata.ecef.vy = (double)getbef32((const char *)buf, 41), |
1363 | 2 | session->newdata.ecef.vz = (double)getbef32((const char *)buf, 45); |
1364 | 2 | mask |= ECEF_SET | VECEF_SET; |
1365 | | |
1366 | 2 | clock_bias = getbed64((const char *)buf, 49); |
1367 | 2 | clock_drift = getbes32(buf, 57); |
1368 | | |
1369 | 2 | session->gpsdata.dop.gdop = getbef32((const char *)buf, 61); |
1370 | 2 | session->gpsdata.dop.pdop = getbef32((const char *)buf, 65); |
1371 | 2 | session->gpsdata.dop.hdop = getbef32((const char *)buf, 69); |
1372 | 2 | session->gpsdata.dop.vdop = getbef32((const char *)buf, 73); |
1373 | 2 | session->gpsdata.dop.tdop = getbef32((const char *)buf, 77); |
1374 | 2 | mask |= DOP_SET; |
1375 | | |
1376 | 2 | session->newdata.time = gpsd_gpstime_resolv(session, wn, ts_tow ); |
1377 | | |
1378 | 2 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1379 | 2 | "Skytraq 0xDF: iod=%u, stat=%u, wn=%u, tow=%f, t=%s " |
1380 | 2 | "cb: %f, cd: %f " |
1381 | 2 | "gdop: %.2f, pdop: %.2f, hdop: %.2f, vdop: %.2f, tdop: %.2f\n", |
1382 | 2 | iod, navstat, wn, f_tow, |
1383 | 2 | timespec_str(&session->newdata.time, ts_buf, sizeof(ts_buf)), |
1384 | 2 | clock_bias, clock_drift, |
1385 | 2 | session->gpsdata.dop.gdop, |
1386 | 2 | session->gpsdata.dop.pdop, |
1387 | 2 | session->gpsdata.dop.hdop, |
1388 | 2 | session->gpsdata.dop.vdop, |
1389 | 2 | session->gpsdata.dop.tdop); |
1390 | | |
1391 | 2 | mask |= TIME_SET | STATUS_SET | MODE_SET | CLEAR_IS | REPORT_IS; |
1392 | 2 | return mask; |
1393 | 2 | } |
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 | 322 | { |
1404 | 322 | int i; |
1405 | 322 | unsigned prn; // GPS sat PRN |
1406 | 322 | unsigned subf; // subframe 1-5 |
1407 | | // the words are preprocessed, not raw, just the 24bits of data |
1408 | 322 | uint32_t words[10]; // subframe 1-5 |
1409 | | |
1410 | 322 | if (33 != len) { |
1411 | 139 | return 0; |
1412 | 139 | } |
1413 | | |
1414 | 183 | prn = (unsigned)getub(buf, 1); |
1415 | 183 | subf = (unsigned)getub(buf, 2); |
1416 | 2.01k | for (i = 0; i < 10; i++) { |
1417 | 1.83k | words[i] = (uint32_t)getbeu24(buf, 3 + (i * 3)); |
1418 | 1.83k | } |
1419 | | |
1420 | 183 | GPSD_LOG(LOG_DATA, &session->context->errout, |
1421 | 183 | "Skytraq 0xE0: prn=%u, subf=%u\n", |
1422 | 183 | prn, subf); |
1423 | | |
1424 | | // could be SBAS? |
1425 | 183 | return gpsd_interpret_subframe(session, GNSSID_GPS, prn, words); |
1426 | 322 | } |
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 | 174 | { |
1440 | 174 | int i; |
1441 | 174 | unsigned prn; // BeidouPS sat PRN 206-214 |
1442 | 174 | unsigned subf; // subframe 1-5 |
1443 | | // the words are preprocessed, not raw, just the 28 bytes of data |
1444 | 174 | uint8_t bytes[28]; // raw data |
1445 | | |
1446 | 174 | if (31 != len) { |
1447 | 173 | return 0; |
1448 | 173 | } |
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 | 174 | } |
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 | 404 | { |
1478 | 404 | int i; |
1479 | 404 | unsigned prn; // BeidouPS sat PRN 201-205 |
1480 | 404 | unsigned subf; // subframe 1-5 |
1481 | | // the words are preprocessed, not raw, just the 28 bytes of data |
1482 | 404 | uint8_t bytes[28]; // raw data |
1483 | | |
1484 | 404 | if (31 != len) { |
1485 | 403 | return 0; |
1486 | 403 | } |
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 | 404 | } |
1503 | | |
1504 | | |
1505 | | static gps_mask_t sky_parse(struct gps_device_t * session, |
1506 | | unsigned char *buf, size_t len) |
1507 | 14.7k | { |
1508 | 14.7k | gps_mask_t mask = 0; |
1509 | | |
1510 | 14.7k | if (0 == len) { |
1511 | 0 | return mask; |
1512 | 0 | } |
1513 | | |
1514 | 14.7k | buf += 4; // skip the leaders and length |
1515 | 14.7k | 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 | 14.7k | switch (buf[0]) { |
1524 | 640 | case 0x62: |
1525 | 640 | mask = sky_msg_62(session, buf, len); |
1526 | 640 | break; |
1527 | 503 | case 0x63: |
1528 | 503 | mask = sky_msg_63(session, buf, len); |
1529 | 503 | break; |
1530 | 1.02k | case 0x64: |
1531 | 1.02k | mask = sky_msg_64(session, buf, len); |
1532 | 1.02k | break; |
1533 | 505 | case 0x65: |
1534 | 505 | mask = sky_msg_65(session, buf, len); |
1535 | 505 | break; |
1536 | 744 | case 0x6A: |
1537 | 744 | mask = sky_msg_6A(session, buf, len); |
1538 | 744 | break; |
1539 | 253 | case 0x7A: |
1540 | 253 | mask = sky_msg_7A(session, buf, len); |
1541 | 253 | break; |
1542 | 254 | case 0x80: |
1543 | | // 128 |
1544 | 254 | mask = sky_msg_80(session, buf, len); |
1545 | 254 | break; |
1546 | 94 | case 0x81: |
1547 | | // Software CRC |
1548 | 94 | mask = sky_msg_81(session, buf, len); |
1549 | 94 | break; |
1550 | 691 | case 0x83: |
1551 | | // 131 - ACK |
1552 | 691 | if (2 == len) { |
1553 | 93 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1554 | 93 | "Skytraq 0x83: ACK MID %#02x\n", buf[1]); |
1555 | 598 | } else if (3 == len) { |
1556 | 120 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1557 | 120 | "Skytraq 0x83: ACK MID %#02x/%02x\n", buf[1], buf[2]); |
1558 | 478 | } else if (4 <= len) { |
1559 | 352 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1560 | 352 | "Skytraq 0x83: ACK MID %#02x/%02x/%02x\n", |
1561 | 352 | buf[1], buf[2], buf[3]); |
1562 | 352 | } else { |
1563 | 126 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1564 | 126 | "Skytraq 0x83: ACK\n"); |
1565 | 126 | } |
1566 | 691 | break; |
1567 | 627 | case 0x84: |
1568 | | // 132 - NACK |
1569 | 627 | if (2 == len) { |
1570 | 134 | GPSD_LOG(LOG_INF, &session->context->errout, |
1571 | 134 | "Skytraq 0x84: NACK MID %#02x\n", buf[1]); |
1572 | 493 | } else if (3 == len) { |
1573 | 108 | GPSD_LOG(LOG_INF, &session->context->errout, |
1574 | 108 | "Skytraq 0x84: NACK MID %#02x/%02x\n", buf[1], buf[2]); |
1575 | 385 | } else if (4 <= len) { |
1576 | 119 | GPSD_LOG(LOG_INF, &session->context->errout, |
1577 | 119 | "Skytraq 0x84: NACK MID %#02x/%02x/x%02x\n", |
1578 | 119 | buf[1], buf[2], buf[3]); |
1579 | 266 | } else { |
1580 | 266 | GPSD_LOG(LOG_INF, &session->context->errout, |
1581 | 266 | "Skytraq 0x84: NACK\n"); |
1582 | 266 | } |
1583 | 627 | break; |
1584 | 146 | case 0x86: |
1585 | | // 134 Position Update Rate |
1586 | 146 | mask = sky_msg_86(session, buf, len); |
1587 | 146 | break; |
1588 | 168 | case 0x89: |
1589 | 168 | mask = sky_msg_89(session, buf, len); |
1590 | 168 | break; |
1591 | 645 | case 0x8A: |
1592 | 645 | mask = sky_msg_8A(session, buf, len); |
1593 | 645 | break; |
1594 | 181 | case 0x8B: |
1595 | 181 | mask = sky_msg_8B(session, buf, len); |
1596 | 181 | break; |
1597 | 362 | case 0x93: |
1598 | | // NMEA TALKER id |
1599 | 362 | mask = sky_msg_93(session, buf, len); |
1600 | 362 | break; |
1601 | | |
1602 | 131 | case 0xA8: |
1603 | | // Navigation Data Message |
1604 | 131 | mask = sky_msg_A8(session, buf, len); |
1605 | 131 | break; |
1606 | | |
1607 | 1.94k | case 0xae: |
1608 | | // GNSS Datum |
1609 | 1.94k | mask = sky_msg_AE(session, buf, len); |
1610 | 1.94k | break; |
1611 | | |
1612 | 142 | case 0xaf: |
1613 | | // DOP Mask |
1614 | 142 | mask = sky_msg_AF(session, buf, len); |
1615 | 142 | break; |
1616 | | |
1617 | 167 | case 0xb0: |
1618 | | // Elevation and CNR mask |
1619 | 167 | mask = sky_msg_B0(session, buf, len); |
1620 | 167 | break; |
1621 | | |
1622 | 133 | case 0xb4: |
1623 | | // Position Pinning Status |
1624 | 133 | mask = sky_msg_B4(session, buf, len); |
1625 | 133 | break; |
1626 | | |
1627 | 296 | case 0xb9: |
1628 | 296 | mask = sky_msg_B9(session, buf, len); |
1629 | 296 | break; |
1630 | | |
1631 | 68 | case 0xbb: |
1632 | 68 | mask = sky_msg_BB(session, buf, len); |
1633 | 68 | break; |
1634 | | |
1635 | 453 | case 0xDC: |
1636 | | // 220 |
1637 | 453 | mask = sky_msg_DC(session, buf, len); |
1638 | 453 | break; |
1639 | | |
1640 | 1.23k | case 0xDD: |
1641 | | // 221 |
1642 | 1.23k | if (3 <= len) { |
1643 | 966 | mask = sky_msg_DD(session, buf, len); |
1644 | 966 | } |
1645 | 1.23k | break; |
1646 | | |
1647 | 1.47k | case 0xDE: |
1648 | | // 222 |
1649 | 1.47k | mask = sky_msg_DE(session, buf, len); |
1650 | 1.47k | break; |
1651 | | |
1652 | 76 | case 0xDF: |
1653 | | // 223 - Nave status (PVT) |
1654 | 76 | mask = sky_msg_DF(session, buf, len); |
1655 | 76 | break; |
1656 | | |
1657 | 322 | case 0xE0: |
1658 | | // 224 |
1659 | 322 | mask = sky_msg_E0(session, buf, len); |
1660 | 322 | break; |
1661 | | |
1662 | 174 | case 0xE2: |
1663 | | // 226 - Beidou2 D1 Subframe data |
1664 | 174 | mask = sky_msg_E2(session, buf, len); |
1665 | 174 | break; |
1666 | | |
1667 | 404 | case 0xE3: |
1668 | | // 227 - Beidou2 D2 Subframe data |
1669 | 404 | mask = sky_msg_E3(session, buf, len); |
1670 | 404 | break; |
1671 | | |
1672 | 133 | case 0x67: // sub-id messages |
1673 | 133 | FALLTHROUGH |
1674 | 280 | case 0x6F: // sub-id messages |
1675 | 280 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1676 | 280 | "Skytraq Unknown MID x%02x SID x%02x length %zd\n", |
1677 | 280 | buf[0], buf[1], len); |
1678 | 280 | break; |
1679 | 650 | default: |
1680 | 650 | GPSD_LOG(LOG_PROG, &session->context->errout, |
1681 | 650 | "Skytraq Unknown MID %#02x length %zd\n", |
1682 | 650 | buf[0], len); |
1683 | 650 | break; |
1684 | 14.7k | } |
1685 | 14.7k | return mask; |
1686 | 14.7k | } |
1687 | | |
1688 | | static gps_mask_t skybin_parse_input(struct gps_device_t *session) |
1689 | 17.7k | { |
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 | 17.7k | if (UINT_MAX != session->cfg_stage) { |
1697 | 9.93k | session->cfg_step++; |
1698 | 9.93k | } |
1699 | | |
1700 | 17.7k | if (UINT_MAX != session->cfg_stage && |
1701 | 9.93k | 3 <= session->cfg_step) { |
1702 | | // more init to do |
1703 | | |
1704 | 3.32k | session->cfg_stage++; |
1705 | 3.32k | 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 | 3.32k | switch (session->cfg_stage) { |
1713 | 168 | case 1: |
1714 | | // Send MID 0x3, to get back MID 0x81 Software CRC |
1715 | 168 | (void)sky_write(session, "\xA0\xA1\x00\x02\x03\x00\x03\x0d\x0a", |
1716 | 168 | 9); |
1717 | 168 | break; |
1718 | 164 | case 2: |
1719 | | // Send MID 0x10, to get back MID 0x86 (Position Update Rate) |
1720 | 164 | (void)sky_write(session, "\xA0\xA1\x00\x01\x10\x10\x0d\x0a", 8); |
1721 | 164 | break; |
1722 | 174 | case 3: |
1723 | | // Send MID 0x15, to get back MID 0xB9 (Power Mode Status) |
1724 | 174 | (void)sky_write(session, "\xA0\xA1\x00\x01\x15\x15\x0d\x0a", 8); |
1725 | 174 | break; |
1726 | 173 | case 4: |
1727 | | // Send MID 0x1f, to get back MID 0x89 Measurement data statuS |
1728 | 173 | (void)sky_write(session, "\xA0\xA1\x00\x01\x1f\x1f\x0d\x0a", 8); |
1729 | 173 | break; |
1730 | 163 | case 5: |
1731 | | // Send MID 0x21, to get back MID 0x8a RTCM Data output status |
1732 | 163 | (void)sky_write(session, "\xA0\xA1\x00\x01\x21\x21\x0d\x0a", 8); |
1733 | 163 | break; |
1734 | 153 | case 6: |
1735 | | // Send MID 0x23, to get back MID 0x8B (Base Position) |
1736 | 153 | (void)sky_write(session, "\xA0\xA1\x00\x01\x23\x23\x0d\x0a", 8); |
1737 | 153 | break; |
1738 | 138 | case 7: |
1739 | | // Send MID 0x2d, to get back MID 0xAE (GNSS Datum) |
1740 | 138 | (void)sky_write(session, "\xA0\xA1\x00\x01\x2d\x2d\x0d\x0a", 8); |
1741 | 138 | break; |
1742 | 145 | case 8: |
1743 | | // Send MID 0x2E, to get back MID 0xAF (DOP Mask) |
1744 | 145 | (void)sky_write(session, "\xA0\xA1\x00\x01\x2e\x2e\x0d\x0a", 8); |
1745 | 145 | break; |
1746 | 134 | case 9: |
1747 | | // Send MID 0x2F, to get back MID 0x80 Elevation and SNR mask |
1748 | 134 | (void)sky_write(session, "\xA0\xA1\x00\x01\x2f\x2f\x0d\x0a", 8); |
1749 | 134 | break; |
1750 | 133 | case 10: |
1751 | | // Send MID 0x3a, to get back MID 0xb4 Position Pinning |
1752 | 133 | (void)sky_write(session, "\xA0\xA1\x00\x01\x3a\x3a\x0d\x0a", 8); |
1753 | 133 | break; |
1754 | 122 | case 11: |
1755 | | // Send MID 0x44, to get back MID 0xc2 1PPS timing |
1756 | | // Timing mode versions only |
1757 | 122 | (void)sky_write(session, "\xA0\xA1\x00\x01\x44\x44\x0d\x0a", 8); |
1758 | 122 | break; |
1759 | 119 | case 12: |
1760 | | // Send MID 0x46, to get back MID 0xbb 1PPS delay |
1761 | 119 | (void)sky_write(session, "\xA0\xA1\x00\x01\x46\x46\x0d\x0a", 8); |
1762 | 119 | break; |
1763 | 116 | case 13: |
1764 | | // Send MID 0x4f, to get back MID 0x93 NMEA talker ID |
1765 | 116 | (void)sky_write(session, "\xA0\xA1\x00\x01\x4f\x4f\x0d\x0a", 8); |
1766 | 116 | break; |
1767 | 106 | case 14: |
1768 | | // Send MID 0x56, to get back MID 0xc3 1PPS Output Mode |
1769 | | // Timing mode versions only |
1770 | 106 | (void)sky_write(session, "\xA0\xA1\x00\x01\x56\x56\x0d\x0a", 8); |
1771 | 106 | break; |
1772 | 96 | case 15: |
1773 | | // Send MID 0x62/02, to get back MID 0x62/80 SBAS status |
1774 | 96 | (void)sky_write(session, |
1775 | 96 | "\xA0\xA1\x00\x02\x62\x02\x60\x0d\x0a", 9); |
1776 | 96 | break; |
1777 | 92 | case 16: |
1778 | | // Send MID 0x62/04, to get back MID 0x62/81 QZSS status |
1779 | 92 | (void)sky_write(session, |
1780 | 92 | "\xA0\xA1\x00\x02\x62\x04\x66\x0d\x0a", 9); |
1781 | 92 | break; |
1782 | 88 | case 17: |
1783 | | // Send MID 0x62/06, to get back MID 0x62/82 SBAS Advanced status |
1784 | 88 | (void)sky_write(session, |
1785 | 88 | "\xA0\xA1\x00\x02\x62\x06\x64\x0d\x0a", 9); |
1786 | 88 | break; |
1787 | 82 | case 18: |
1788 | | // Send MID 0x63/02, to get back MID 0x62/80 SAEE Status |
1789 | | // not on PX1172RH_DS |
1790 | 82 | (void)sky_write(session, |
1791 | 82 | "\xA0\xA1\x00\x02\x63\x02\x61\x0d\x0a", 9); |
1792 | 82 | break; |
1793 | 75 | case 19: |
1794 | | // Send MID 0x64/01, to get back MID 0x64/80 |
1795 | 75 | (void)sky_write(session, |
1796 | 75 | "\xA0\xA1\x00\x02\x64\x01\x65\x0d\x0a", 9); |
1797 | 75 | break; |
1798 | 68 | case 20: |
1799 | | // Send MID 0x64/03, to get back MID 0x64/81 |
1800 | 68 | (void)sky_write(session, |
1801 | 68 | "\xA0\xA1\x00\x02\x64\x03\x67\x0d\x0a", 9); |
1802 | 68 | break; |
1803 | 65 | case 21: |
1804 | | // Send MID 0x64/07, to get back MID 0x64/83 |
1805 | 65 | (void)sky_write(session, |
1806 | 65 | "\xA0\xA1\x00\x02\x64\x07\x63\x0d\x0a", 9); |
1807 | 65 | break; |
1808 | 59 | case 22: |
1809 | | // Send MID 0x64/0b, to get back MID 0x64/85 |
1810 | 59 | (void)sky_write(session, |
1811 | 59 | "\xA0\xA1\x00\x02\x64\x0b\x6f\x0d\x0a", 9); |
1812 | 59 | break; |
1813 | 53 | case 23: |
1814 | | // Send MID 0x64/12, to get back MID 0x64/88 |
1815 | 53 | (void)sky_write(session, |
1816 | 53 | "\xA0\xA1\x00\x02\x64\x12\x76\x0d\x0a", 9); |
1817 | 53 | break; |
1818 | 53 | case 24: |
1819 | | // Send MID 0x64/16, to get back MID 0x64/8a |
1820 | 53 | (void)sky_write(session, |
1821 | 53 | "\xA0\xA1\x00\x02\x64\x16\x72\x0d\x0a", 9); |
1822 | 53 | break; |
1823 | 51 | case 25: |
1824 | | // Send MID 0x64/18, to get back MID 0x64/8b |
1825 | 51 | (void)sky_write(session, |
1826 | 51 | "\xA0\xA1\x00\x02\x64\x18\x7c\x0d\x0a", 9); |
1827 | 51 | break; |
1828 | 50 | case 26: |
1829 | | // Send MID 0x64/1a, to get back MID 0x64/8c |
1830 | 50 | (void)sky_write(session, |
1831 | 50 | "\xA0\xA1\x00\x02\x64\x1a\x7e\x0d\x0a", 9); |
1832 | 50 | break; |
1833 | 46 | case 27: |
1834 | | // Send MID 0x64/20, to get back MID 0x64/8e |
1835 | 46 | (void)sky_write(session, |
1836 | 46 | "\xA0\xA1\x00\x02\x64\x20\x44\x0d\x0a", 9); |
1837 | 46 | break; |
1838 | 43 | case 28: |
1839 | | // Send MID 0x64/22, to get back MID 0x64/8f |
1840 | | // not on PX1172RH_DS |
1841 | 43 | (void)sky_write(session, |
1842 | 43 | "\xA0\xA1\x00\x02\x64\x22\x46\x0d\x0a", 9); |
1843 | 43 | break; |
1844 | 38 | case 29: |
1845 | | // Send MID 0x64/28, to get back MID 0x64/92 |
1846 | 38 | (void)sky_write(session, |
1847 | 38 | "\xA0\xA1\x00\x02\x64\x28\x4c\x0d\x0a", 9); |
1848 | 38 | break; |
1849 | 36 | case 30: |
1850 | | // Send MID 0x64/30, to get back MID 0x64/98 |
1851 | | // not on PX1172RH_DS |
1852 | 36 | (void)sky_write(session, |
1853 | 36 | "\xA0\xA1\x00\x02\x64\x30\x54\x0d\x0a", 9); |
1854 | 36 | break; |
1855 | 35 | case 31: |
1856 | | // Send MID 0x64/31, to get back MID 0x64/ |
1857 | | // not on PX1172RH_DS |
1858 | 35 | (void)sky_write(session, |
1859 | 35 | "\xA0\xA1\x00\x02\x64\x31\x55\x0d\x0a", 9); |
1860 | 35 | break; |
1861 | 31 | case 32: |
1862 | | // Send MID 0x64/7d, to get back MID 0x64/fe |
1863 | 31 | (void)sky_write(session, |
1864 | 31 | "\xA0\xA1\x00\x02\x64\x7d\x19\x0d\x0a", 9); |
1865 | 31 | break; |
1866 | 29 | case 33: |
1867 | | // Send MID 0x64/35, to get back MID 0x64/99 |
1868 | | // not on PX1172RH_DS |
1869 | 29 | (void)sky_write(session, |
1870 | 29 | "\xA0\xA1\x00\x03\x64\x35\x01\x50\x0d\x0a", 10); |
1871 | 29 | break; |
1872 | 26 | case 34: |
1873 | | // Send MID 0x64/36, to get back MID 0x64/9a |
1874 | | // not on PX1172RH_DS |
1875 | 26 | (void)sky_write(session, |
1876 | 26 | "\xA0\xA1\x00\x02\x64\x36\x52\x0d\x0a", 9); |
1877 | 26 | break; |
1878 | 24 | case 35: |
1879 | | // Send MID 0x64/3c, to get back MID 0x64/99 |
1880 | | // not on PX1172RH_DS |
1881 | 24 | (void)sky_write(session, |
1882 | 24 | "\xA0\xA1\x00\x04\x64\x3c\x47\x47\x19\x0d\x0a", |
1883 | 24 | 11); |
1884 | 24 | break; |
1885 | 22 | case 36: |
1886 | | // Send MID 0x65/02, to get back MID 0x64/80 |
1887 | 22 | (void)sky_write(session, |
1888 | 22 | "\xA0\xA1\x00\x02\x65\x02\x67\x0d\x0a", 9); |
1889 | 22 | break; |
1890 | 22 | case 37: |
1891 | | // Send MID 0x65/04, to get back MID 0x64/8f |
1892 | 22 | (void)sky_write(session, |
1893 | 22 | "\xA0\xA1\x00\x02\x65\x04\x61\x0d\x0a", 9); |
1894 | 22 | break; |
1895 | 19 | case 38: |
1896 | | // Send MID 0x6a/02, to get back MID 0x6a/83 |
1897 | 19 | (void)sky_write(session, |
1898 | 19 | "\xA0\xA1\x00\x02\x6a\x02\x68\x0d\x0a", 9); |
1899 | 19 | break; |
1900 | 16 | case 39: |
1901 | | // Send MID 0x6a/07, to get back MID 0x6a/83 |
1902 | 16 | (void)sky_write(session, |
1903 | 16 | "\xA0\xA1\x00\x02\x6a\x07\x6d\x0d\x0a", 9); |
1904 | 16 | break; |
1905 | 16 | case 40: |
1906 | | // Send MID 0x6a/0d, to get back MID 0x6a/85 |
1907 | 16 | (void)sky_write(session, |
1908 | 16 | "\xA0\xA1\x00\x02\x6a\x0d\x67\x0d\x0a", 9); |
1909 | 16 | break; |
1910 | 15 | case 41: |
1911 | | // Send MID 0x6a/14, to get back MID 0x6a/86 |
1912 | 15 | (void)sky_write(session, |
1913 | 15 | "\xA0\xA1\x00\x02\x6a\x14\xfd\x0d\x0a", 9); |
1914 | 15 | break; |
1915 | 11 | case 42: |
1916 | | // Send MID 0x6a/16, to get back MID 0x6a/89 |
1917 | | // not on PX1172RH_DS ? |
1918 | 11 | (void)sky_write(session, |
1919 | 11 | "\xA0\xA1\x00\x02\x6a\x16\x7c\x0d\x0a", 9); |
1920 | 11 | break; |
1921 | 11 | case 43: |
1922 | | // Send MID 0x7a/0e/01, to get back MID 0x7a/0e/80 |
1923 | | // not on PX1172RH_DS ? |
1924 | 11 | (void)sky_write(session, |
1925 | 11 | "\xA0\xA1\x00\x03\x7a\x0e\x01\x75\x0d\x0a", 10); |
1926 | 11 | break; |
1927 | 11 | case 44: |
1928 | | // Send MID 0x7a/0e/02, to get back MID 0x7a/0e/81 |
1929 | | // not on PX1172RH_DS ? |
1930 | 11 | (void)sky_write(session, |
1931 | 11 | "\xA0\xA1\x00\x03\x7a\x0e\x02\x76\x0d\x0a", 10); |
1932 | 11 | break; |
1933 | 11 | case 45: |
1934 | | // Send MID 0x7a/0e/03, to get back MID 0x7a/0e/82 |
1935 | | // not on PX1172RH_DS ? |
1936 | 11 | (void)sky_write(session, |
1937 | 11 | "\xA0\xA1\x00\x03\x7a\x0e\x03\x77\x0d\x0a", 10); |
1938 | 11 | break; |
1939 | 9 | case 46: |
1940 | | // Send MID 0x7a/0e/05, to get back MID 0x7a/0e/83 |
1941 | | // not on PX1172RH_DS ? |
1942 | 9 | (void)sky_write(session, |
1943 | 9 | "\xA0\xA1\x00\x03\x7a\x0e\x05\x71\x0d\x0a", 10); |
1944 | 9 | break; |
1945 | 9 | default: |
1946 | | // Done |
1947 | 9 | session->cfg_stage = UINT_MAX; |
1948 | 9 | break; |
1949 | 3.32k | } |
1950 | 3.32k | } |
1951 | | |
1952 | 17.7k | if (SKY_PACKET == session->lexer.type) { |
1953 | 14.7k | return sky_parse(session, session->lexer.outbuffer, |
1954 | 14.7k | session->lexer.outbuflen); |
1955 | 14.7k | } |
1956 | 2.98k | if (NMEA_PACKET == session->lexer.type) { |
1957 | 2.98k | return nmea_parse((char *)session->lexer.outbuffer, session); |
1958 | 2.98k | } |
1959 | | // should not get here... |
1960 | | |
1961 | 0 | return 0; |
1962 | 2.98k | } |
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 |