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