1 /*
2 * This file contains two drivers for Garmin receivers and some code
3 * shared by both drivers.
4 *
5 * One driver "garmin_usb_binary" handles the Garmin binary packet
6 * format supported by the USB Garmins tested with the Garmin 18 and
7 * other models. (There is also "garmin_usb_binary_old".) These are ONLY
8 * for USB devices reporting as: 091e:0003.
9 *
10 * The other driver "garmin_ser_binary" is for Garmin receivers via a
11 * serial port, whether or not one uses a USB/serial adaptor or a real
12 * serial port. These receivers provide adequate NMEA support, so it
13 * often makes sense to just put them into NMEA mode.
14 *
15 * On Linux, USB Garmins (091e:0003) need the Linux garmin_gps driver and
16 * will not function without it. On other operating systems, it is clear
17 * garmin_usb_binary_old does not work since it requires the Linux
18 * garmin_gps module.
19 *
20 * This code has been tested and at least at one time is known to work on
21 * big- and little-endian CPUs and 32 and 64 bit cpu modes.
22 *
23 *
24 * Documentation for the Garmin protocols can be found via
25 * http://www.garmin.com/support/commProtocol.html
26 * The file IOSDK.zip contains IntfSpec.pdf, which describes the
27 * protocol in terms of Application, Link, and Physical. This
28 * identical file is also available at:
29 * http://www.garmin.com/support/pdf/iop_spec.pdf
30 * An older version of iop_spec.pdf that describes only Serial Binary
31 * is available at:
32 * http://vancouver-webpages.com/pub/peter/iop_spec.pdf
33 * Information about the GPS 18
34 * http://www.garmin.com/manuals/425_TechnicalSpecification.pdf
35 *
36 * There is one physical link protocol for serial which uses DLE/ETX
37 * framing. There is another physical protocol for USB which relies
38 * on the packetization intrinsic to USB bulk pipes.
39 *
40 * There are several link protocols; all devices implement L000.
41 * There are then product-specific protocols; most devices implement
42 * L001. Link protocols are the same and carried over either Physical
43 * protocol.
44 *
45 * Application protocols are named A000 and then with different
46 * 3-digit numbers. They are carried over Link protocols.
47 *
48 * Thus, much of the higher-level code dealing the data formats is
49 * shared between USB Binary and Serial Binary.
50 *
51 * This code is partly from the Garmin IOSDK and partly from the
52 * sample code in the Linux garmin_gps driver.
53 *
54 * bad code by: Gary E. Miller <gem@rellim.com>
55 *
56 * -D 3 = packet trace
57 * -D 4 = packet details
58 * -D 5 = more packet details
59 * -D 6 = very excessive details
60 *
61 * limitations:
62 *
63 * do not have from garmin:
64 * pdop
65 * hdop
66 * vdop
67 * magnetic variation
68 *
69 * known bugs:
70 * hangs in the fread loop instead of keeping state and returning.
71 *
72 * TODO:
73 *
74 * ?? Add probe function for Serial Binary to start PVT output.
75 *
76 * This file is Copyright (c) 2010-2019 by the GPSD project
77 * SPDX-License-Identifier: BSD-2-clause
78 */
79
80 #include "gpsd_config.h" /* must be before all includes */
81
82 #ifdef GARMIN_ENABLE
83
84 #include <errno.h>
85 #include <math.h>
86 #include <stdbool.h>
87 #include <stdio.h>
88 #include <string.h>
89 #include <time.h>
90 #include <unistd.h>
91
92 #if defined(HAVE_LIBUSB)
93 #include <libusb.h>
94 #endif
95
96 #include "gpsd.h"
97 #include "bits.h"
98 #include "timespec.h"
99
100 #define GPSD_LE16TOH(x) getles16((char *)(&(x)), 0)
101 #define GPSD_LE32TOH(x) getles32((char *)(&(x)), 0)
102 #define GPSD_LEF32(x) getlef32((const char *)(&(x)), 0)
103 #define GPSD_LED64(x) getled64((const char *)(&(x)), 0)
104
105 #define USE_RMD 0
106
107 /* Used in Serial Physical Layer */
108 #define ETX 0x03
109 #define ACK 0x06
110 #define DLE 0x10
111 #define NAK 0x15
112
113 #define GARMIN_LAYERID_TRANSPORT (uint8_t) 0
114 #define GARMIN_LAYERID_APPL (uint32_t) 20
115 // Linux Garmin USB driver layer-id to use for some control mechanisms
116 #define GARMIN_LAYERID_PRIVATE 0x01106E4B
117
118 // packet ids used in private layer
119 #define PRIV_PKTID_SET_DEBUG 1
120 #define PRIV_PKTID_SET_MODE 2
121 #define PRIV_PKTID_INFO_REQ 3
122 #define PRIV_PKTID_INFO_RESP 4
123 #define PRIV_PKTID_RESET_REQ 5
124 #define PRIV_PKTID_SET_DEF_MODE 6
125
126 #define MODE_NATIVE 0
127 #define MODE_GARMIN_SERIAL 1
128
129 #define GARMIN_PKTID_TRANSPORT_START_SESSION_REQ 5
130 #define GARMIN_PKTID_TRANSPORT_START_SESSION_RESP 6
131
132 #define GARMIN_PKTID_PROTOCOL_ARRAY 253
133 #define GARMIN_PKTID_PRODUCT_RQST 254
134 #define GARMIN_PKTID_PRODUCT_DATA 255
135 /* 0x29 ')' */
136 #define GARMIN_PKTID_RMD41_DATA 41
137 /* 0x33 '3' */
138 #define GARMIN_PKTID_PVT_DATA 51
139 /* 0x33 '4' */
140 #define GARMIN_PKTID_RMD_DATA 52
141 /* 0x72 'r' */
142 #define GARMIN_PKTID_SAT_DATA 114
143
144 #define GARMIN_PKTID_L001_XFER_CMPLT 12
145 #define GARMIN_PKTID_L001_COMMAND_DATA 10
146 #define GARMIN_PKTID_L001_DATE_TIME_DATA 14
147 #define GARMIN_PKTID_L001_RECORDS 27
148 #define GARMIN_PKTID_L001_WPT_DATA 35
149
150 #define CMND_ABORT 0
151 #define CMND_START_PVT_DATA 49
152 #define CMND_STOP_PVT_DATA 50
153 #define CMND_START_RM_DATA 110
154
155 #define MAX_BUFFER_SIZE 4096
156
157 #define GARMIN_CHANNELS 12
158
159 // something magic about 64, garmin driver will not return more than
160 // 64 at a time. If you read less than 64 bytes the next read will
161 // just get the last of the 64 byte buffer.
162 #define ASYNC_DATA_SIZE 64
163
164
165 #pragma pack(1)
166 // This is the data format of the satellite data from the garmin USB
167 typedef struct __attribute__((__packed__))
168 {
169 uint8_t svid;
170 uint16_t snr; // 0 - 0xffff
171 uint8_t elev;
172 uint16_t azmth;
173 uint8_t status; // bit 0, has ephemeris, 1, has diff correction
174 // bit 2 used in solution
175 // bit 3??
176 } cpo_sat_data;
177
178 /* Garmin D800_Pvt_Datetype_Type */
179 /* packet type: GARMIN_PKTID_PVT_DATA 52 */
180 /* This is the data format of the position data from the garmin USB */
181 typedef struct __attribute__((__packed__))
182 {
183 float alt; /* altitude above WGS 84 (meters) */
184 float epe; /* estimated position error, 2 sigma (meters) */
185 float eph; /* epe, but horizontal only (meters) */
186 float epv; /* epe but vertical only (meters ) */
187 int16_t fix; /* 0 - failed integrity check
188 * 1 - invalid or unavailable fix
189 * 2 - 2D
190 * 3 - 3D
191 * 4 - 2D Diff
192 * 5 - 3D Diff
193 */
194 double gps_tow; /* gps time of week (seconds) */
195 double lat; /* ->latitude (radians) */
196 double lon; /* ->longitude (radians) */
197 float lon_vel; /* velocity east (meters/second) */
198 float lat_vel; /* velocity north (meters/second) */
199 float alt_vel; /* velocity up (meters/sec) */
200 // Garmin GPS25 uses pkt_id 0x28 and does not output the
201 // next 3 items
202 float msl_hght; /* height of WGS 84 above MSL (meters) */
203 int16_t leap_sec; /* diff between GPS and UTC (seconds) */
204 int32_t grmn_days; /* days from UTC December 31st, 1989 to the
205 * beginning of the current week */
206 } cpo_pvt_data;
207
208 typedef struct __attribute__((__packed__))
209 {
210 uint32_t cycles;
211 double pr; // psuedorange in meters
212 uint16_t phase;
213 int8_t slp_dtct;
214 uint8_t snr_dbhz;
215 uint8_t svid;
216 int8_t valid;
217 } cpo_rcv_sv_data;
218
219 /* packet type: GARMIN_PKTID_RMD_DATA 53 */
220 /* seems identical to the packet id 0x29 from the Garmin GPS 25 */
221 typedef struct __attribute__((__packed__))
222 {
223 double rcvr_tow;
224 int16_t rcvr_wn;
225 cpo_rcv_sv_data sv[GARMIN_CHANNELS];
226 } cpo_rcv_data;
227
228 // This is the packet format to/from the Garmin USB
229 typedef struct __attribute__((__packed__))
230 {
231 uint8_t mPacketType;
232 uint8_t mReserved1;
233 uint16_t mReserved2;
234 uint16_t mPacketId;
235 uint16_t mReserved3;
236 uint32_t mDataSize;
237 union
238 {
239 //int8_t chars[MAX_BUFFER_SIZE];
240 // cppcheck-suppress unusedStructMember
241 uint8_t uchars[MAX_BUFFER_SIZE];
242 cpo_pvt_data pvt;
243 cpo_sat_data sats;
244 } mData;
245 } Packet_t;
246
247 // useful funcs to read/write ints
248 // floats and doubles are Intel (little-endian) order only...
set_int16(uint8_t * buf,uint32_t value)249 static inline void set_int16(uint8_t * buf, uint32_t value)
250 {
251 buf[0] = (uint8_t) (0x0FF & value);
252 buf[1] = (uint8_t) (0x0FF & (value >> 8));
253 }
254
set_int32(uint8_t * buf,uint32_t value)255 static inline void set_int32(uint8_t * buf, uint32_t value)
256 {
257 buf[0] = (uint8_t) (0x0FF & value);
258 buf[1] = (uint8_t) (0x0FF & (value >> 8));
259 buf[2] = (uint8_t) (0x0FF & (value >> 16));
260 buf[3] = (uint8_t) (0x0FF & (value >> 24));
261 }
262
get_uint16(const uint8_t * buf)263 static inline uint16_t get_uint16(const uint8_t * buf)
264 {
265 return (uint16_t) (0xFF & buf[0])
266 | ((uint16_t) (0xFF & buf[1]) << 8);
267 }
268
269 #if defined(HAVE_LIBUSB) && defined(__linux__)
get_int32(const uint8_t * buf)270 static inline uint32_t get_int32(const uint8_t * buf)
271 {
272 return (uint32_t) (0xFF & buf[0])
273 | ((uint32_t) (0xFF & buf[1]) << 8)
274 | ((uint32_t) (0xFF & buf[2]) << 16)
275 | ((uint32_t) (0xFF & buf[3]) << 24);
276 }
277 #endif /* HAVE_LIBUSB */
278
279 // convert radians to degrees
radtodeg(double rad)280 static inline double radtodeg(double rad)
281 {
282 return (double)(rad * RAD_2_DEG);
283 }
284
285 static gps_mask_t PrintSERPacket(struct gps_device_t *session,
286 unsigned char pkt_id, int pkt_len,
287 unsigned char *buf);
288 #if defined(HAVE_LIBUSB) && defined(__linux__)
289 static gps_mask_t PrintUSBPacket(struct gps_device_t *session,
290 Packet_t * pkt);
291 #endif /* HAVE_LIBUSB */
292
PrintSERPacket(struct gps_device_t * session,unsigned char pkt_id,int pkt_len,unsigned char * buf)293 gps_mask_t PrintSERPacket(struct gps_device_t *session, unsigned char pkt_id,
294 int pkt_len, unsigned char *buf)
295 {
296
297 gps_mask_t mask = ONLINE_SET;
298 int i = 0, j = 0;
299 uint16_t prod_id = 0;
300 uint16_t ver = 0;
301 int maj_ver;
302 int min_ver;
303 time_t time_l = 0;
304 char msg_buf[512] = "";
305 char *msg = NULL;
306 cpo_sat_data *sats = NULL;
307 cpo_pvt_data *pvt = NULL;
308 cpo_rcv_data *rmd = NULL;
309 double gps_tow = 0;
310
311 GPSD_LOG(LOG_DATA, &session->context->errout,
312 "Garmin: PrintSERPacket(, %#02x, %#02x, )\n", pkt_id, pkt_len);
313
314 session->cycle_end_reliable = true;
315
316 switch (pkt_id) {
317 case ACK:
318 GPSD_LOG(LOG_PROG, &session->context->errout, "Garmin: ACK\n");
319 break;
320 case NAK:
321 GPSD_LOG(LOG_PROG, &session->context->errout, "Garmin: NAK\n");
322 break;
323 case GARMIN_PKTID_L001_COMMAND_DATA:
324 prod_id = get_uint16((uint8_t *) buf);
325 switch (prod_id) {
326 case CMND_ABORT:
327 msg = "Abort current xfer";
328 break;
329 case CMND_START_PVT_DATA:
330 msg = "Start Xmit PVT data";
331 break;
332 case CMND_STOP_PVT_DATA:
333 msg = "Stop Xmit PVT data";
334 break;
335 case CMND_START_RM_DATA:
336 msg = "Start RMD data";
337 break;
338 default:
339 (void)snprintf(msg_buf, sizeof(msg_buf), "Unknown: %u",
340 (unsigned int)prod_id);
341 msg = msg_buf;
342 break;
343 }
344 GPSD_LOG(LOG_PROG, &session->context->errout,
345 "Garmin: Appl, Command Data: %s\n", msg);
346 break;
347 case GARMIN_PKTID_PRODUCT_RQST:
348 GPSD_LOG(LOG_PROG, &session->context->errout,
349 "Garmin: Appl, Product Data req\n");
350 break;
351 case GARMIN_PKTID_PRODUCT_DATA:
352 prod_id = get_uint16((uint8_t *) buf);
353 ver = get_uint16((uint8_t *) & buf[2]);
354 maj_ver = (int)(ver / 100);
355 min_ver = (int)(ver - (maj_ver * 100));
356 GPSD_LOG(LOG_PROG, &session->context->errout,
357 "Garmin: Appl, Product Data, sz: %d\n",
358 pkt_len);
359 (void)snprintf(session->subtype, sizeof(session->subtype),
360 "%d: %d.%02d", (int)prod_id, maj_ver, min_ver);
361 GPSD_LOG(LOG_INF, &session->context->errout,
362 "Garmin: Product ID: %d, SoftVer: %d.%02d\n",
363 prod_id, maj_ver, min_ver);
364 GPSD_LOG(LOG_INF, &session->context->errout,
365 "Garmin: Product Desc: %s\n", &buf[4]);
366 mask |= DEVICEID_SET;
367 GPSD_LOG(LOG_DATA, &session->context->errout,
368 "Garmin: PRODUCT_DATA: subtype=%s\n",
369 session->subtype);
370 break;
371 case GARMIN_PKTID_PVT_DATA:
372 GPSD_LOG(LOG_PROG, &session->context->errout,
373 "Garmin: PVT Data (51) Sz: %d\n", pkt_len);
374
375 pvt = (cpo_pvt_data *) buf;
376
377 session->context->leap_seconds = (int)GPSD_LE16TOH(pvt->leap_sec);
378 session->context->valid = LEAP_SECOND_VALID;
379
380 // 631065600, unix seconds for 31 Dec 1989 Zulu
381 time_l = (time_t) (631065600 + (GPSD_LE32TOH(pvt->grmn_days) * 86400));
382 // TODO, convert grmn_days to context->gps_week
383 time_l -= session->context->leap_seconds;
384
385 // gps_tow is always like x.999 or x.998 just round it to nearest sec
386 // FIXME! this will break 5Hz garmins...
387 gps_tow = GPSD_LED64(pvt->gps_tow);
388 time_l += (time_t)round(gps_tow);
389
390 /* sanity check unix time against leap second.
391 * Leap second 18 at 1 Jan 2017: 1483228800 */
392 if (17 < session->context->leap_seconds &&
393 1483228800L > time_l) {
394 time_l += 619315200; // fast forward 1024 weeks
395 }
396
397 DTOTS(&session->context->gps_tow, gps_tow);
398 session->newdata.time.tv_sec = time_l;
399 session->newdata.time.tv_nsec = 0;
400 // (long long) for 32-bit systems
401 GPSD_LOG(LOG_PROG, &session->context->errout,
402 "Garmin: time_l: %lld\n", (long long)time_l);
403
404 session->newdata.latitude = radtodeg(GPSD_LED64(pvt->lat));
405 session->newdata.longitude = radtodeg(GPSD_LED64(pvt->lon));
406 // altitude is WGS84
407 session->newdata.altHAE = GPSD_LEF32(pvt->alt);
408
409 // geoid separation from WGS 84
410 // gpsd sign is opposite of garmin sign
411 session->newdata.geoid_sep = -GPSD_LEF32(pvt->msl_hght);
412
413 /* Estimated position error in meters. Confidence (sigma) not
414 * specified by Garmin.
415 * We follow the advice at <http://gpsinformation.net/main/errors.htm>.
416 * Since GPS data is not gaussian, this is marginal advice...
417 * If this assumption changes here, it should also change in
418 * nmea_parse.c where we analyze PGRME.
419 */
420 session->newdata.sep = GPSD_LEF32(pvt->epe) *
421 (GPSD_CONFIDENCE / CEP50_SIGMA);
422 /* eph, horizaontal error, 2 sigma */
423 session->newdata.eph = GPSD_LEF32(pvt->eph) *
424 (GPSD_CONFIDENCE / CEP50_SIGMA);
425 /* eph, horizaontal error, 2 sigma */
426 session->newdata.epv = GPSD_LEF32(pvt->epv) *
427 (GPSD_CONFIDENCE / CEP50_SIGMA);
428
429 /* meters/sec */
430 session->newdata.NED.velN = GPSD_LEF32(pvt->lat_vel);
431 session->newdata.NED.velE = GPSD_LEF32(pvt->lon_vel);
432 session->newdata.NED.velD = -GPSD_LEF32(pvt->alt_vel);
433
434 switch (GPSD_LE16TOH(pvt->fix)) {
435 case 0:
436 case 1:
437 default:
438 // no fix
439 session->gpsdata.status = STATUS_NO_FIX;
440 session->newdata.mode = MODE_NO_FIX;
441 break;
442 case 2:
443 // 2D fix
444 session->gpsdata.status = STATUS_FIX;
445 session->newdata.mode = MODE_2D;
446 break;
447 case 3:
448 // 3D fix
449 session->gpsdata.status = STATUS_FIX;
450 session->newdata.mode = MODE_3D;
451 break;
452 case 4:
453 // 2D Differential fix
454 session->gpsdata.status = STATUS_DGPS_FIX;
455 session->newdata.mode = MODE_2D;
456 break;
457 case 5:
458 // 3D differential fix
459 session->gpsdata.status = STATUS_DGPS_FIX;
460 session->newdata.mode = MODE_3D;
461 break;
462 }
463
464 GPSD_LOG(LOG_PROG, &session->context->errout,
465 "Garmin: Appl, mode %d, status %d\n",
466 session->newdata.mode, session->gpsdata.status);
467
468 /* save some expensive calculations if not needed */
469 if (session->context->errout.debug >= LOG_INF) {
470
471 GPSD_LOG(LOG_INF, &session->context->errout,
472 "Garmin: UTC Time: %lld\n",
473 (long long)session->newdata.time.tv_sec);
474 GPSD_LOG(LOG_INF, &session->context->errout,
475 "Garmin: Geoid Separation (MSL-WGS84): from garmin %lf, "
476 "calculated %lf\n",
477 session->newdata.geoid_sep,
478 wgs84_separation(session->newdata.latitude,
479 session->newdata.longitude));
480
481 GPSD_LOG(LOG_INF, &session->context->errout,
482 "Garmin: Alt: %.3f, sep: %.3f, eph: %.3f, Epv: %.3f, "
483 "Fix: %d, Gps_tow: %f, Lat: %.3f, Lon: %.3f, "
484 "velN: %.3f, velE: %.3f, velD: %.3f, geoidsep: %.3f, "
485 "Leap: %d, GarminDays: %d\n",
486 session->newdata.altHAE,
487 session->newdata.sep,
488 session->newdata.eph,
489 session->newdata.epv,
490 GPSD_LE16TOH(pvt->fix),
491 gps_tow,
492 session->newdata.latitude,
493 session->newdata.longitude,
494 session->newdata.NED.velN,
495 session->newdata.NED.velE,
496 session->newdata.NED.velD,
497 session->newdata.geoid_sep,
498 session->context->leap_seconds,
499 GPSD_LE32TOH(pvt->grmn_days));
500 }
501
502 if (session->newdata.mode > MODE_NO_FIX) {
503 /* data only valid with a fix */
504 mask |=
505 TIME_SET | LATLON_SET | ALTITUDE_SET | STATUS_SET | MODE_SET |
506 HERR_SET | PERR_IS | CLEAR_IS | REPORT_IS | VNED_SET;
507 /*
508 * Garmin documentation says we should wait until four good fixes
509 * have been seen before trying to use the device for precision
510 * time service.
511 */
512 if (session->fixcnt > 3)
513 mask |= NTPTIME_IS;
514 }
515 GPSD_LOG(LOG_DATA, &session->context->errout,
516 "Garmin: PVT_DATA: time=%lld, lat=%.2f lon=%.2f "
517 "eph=%.2f sep=%.2f epv=%.2f mode=%d status=%d\n",
518 (long long)session->newdata.time.tv_sec,
519 session->newdata.latitude,
520 session->newdata.longitude,
521 session->newdata.eph,
522 session->newdata.sep,
523 session->newdata.epv,
524 session->newdata.mode,
525 session->gpsdata.status);
526 break;
527 case GARMIN_PKTID_RMD_DATA:
528 case GARMIN_PKTID_RMD41_DATA:
529 rmd = (cpo_rcv_data *) buf;
530 GPSD_LOG(LOG_DATA, &session->context->errout,
531 "Garmin: PVT RMD Data Sz: %d\n", pkt_len);
532 GPSD_LOG(LOG_PROG, &session->context->errout,
533 "Garmin: PVT RMD rcvr_tow: %f, rcvr_wn: %d\n",
534 GPSD_LED64(rmd->rcvr_tow), GPSD_LE16TOH(rmd->rcvr_wn));
535 for (i = 0; i < GARMIN_CHANNELS; i++) {
536 GPSD_LOG(LOG_INF, &session->context->errout,
537 "Garmin: PVT RMD Sat: %3u, cycles: %9u, pr: %16.6f, "
538 "phase: %7.3f, slp_dtct: %3s, snr: %3u, Valid: %3s\n",
539 (int)rmd->sv[i].svid + 1,
540 GPSD_LE32TOH(rmd->sv[i].cycles),
541 GPSD_LED64(rmd->sv[i].pr),
542 (GPSD_LE16TOH(rmd->sv[i].phase) * 360.0) / 2048.0,
543 rmd->sv[i].slp_dtct != 0 ? "Yes" : "No",
544 rmd->sv[i].snr_dbhz,
545 rmd->sv[i].valid != 0 ? "Yes" : "No");
546 }
547 break;
548
549 case GARMIN_PKTID_SAT_DATA:
550 // record ID 0x72 (114)
551 GPSD_LOG(LOG_PROG, &session->context->errout,
552 "Garmin: SAT Data Sz: %d\n", pkt_len);
553 sats = (cpo_sat_data *) buf;
554
555 session->gpsdata.satellites_used = 0;
556 gpsd_zero_satellites(&session->gpsdata);
557 for (i = 0, j = 0; i < GARMIN_CHANNELS; i++, sats++) {
558 GPSD_LOG(LOG_INF, &session->context->errout,
559 "Garmin: Sat %2d, snr: %5u, elev: %2d, Azmth: %3d, "
560 "Stat: x%x\n",
561 sats->svid, GPSD_LE16TOH(sats->snr), sats->elev,
562 GPSD_LE16TOH(sats->azmth),
563 sats->status);
564
565 if (255 == (int)sats->svid) {
566 // Garmin uses 255 for empty
567 // gpsd uses 0 for empty
568 continue;
569 }
570
571 if ((int)sats->svid <= 32) {
572 /* GPS 1-32 */
573 session->gpsdata.skyview[j].PRN = (short)sats->svid;
574 session->gpsdata.skyview[j].svid = (short)sats->svid;
575 session->gpsdata.skyview[j].gnssid = GNSSID_GPS;
576 } else {
577 /* SBAS 33-64 */
578 session->gpsdata.skyview[j].PRN = (short)sats->svid;
579 session->gpsdata.skyview[j].svid = (short)sats->svid + 87;
580 session->gpsdata.skyview[j].gnssid = GNSSID_SBAS;
581 }
582 session->gpsdata.skyview[j].azimuth =
583 (short)GPSD_LE16TOH(sats->azmth);
584 session->gpsdata.skyview[j].elevation = (short)sats->elev;
585 if (0xffff == sats->snr) {
586 session->gpsdata.skyview[j].ss = NAN;
587 } else {
588 // Garmin does not document this. snr is in dB*100
589 // Known, but not seen satellites have a dB value of -1*100
590 session->gpsdata.skyview[j].ss =
591 (float)(GPSD_LE16TOH(sats->snr) / 100.0);
592 }
593 // FIX-ME: Garmin documents this, but Daniel Dorau
594 // <daniel.dorau@gmx.de> says the behavior on his GPSMap60CSX
595 // doesn't match it.
596 if ((uint8_t) 0 != (sats->status & 4)) {
597 // used in solution?
598 session->gpsdata.skyview[j].used = true;
599 session->gpsdata.satellites_used++;
600 }
601 session->gpsdata.satellites_visible++;
602 j++;
603
604 }
605 session->gpsdata.skyview_time.tv_sec = 0;
606 session->gpsdata.skyview_time.tv_nsec = 0;
607 mask |= USED_IS | SATELLITE_SET;
608 GPSD_LOG(LOG_DATA, &session->context->errout,
609 "Garmin: SAT_DATA: visible=%d used=%d\n",
610 session->gpsdata.satellites_visible,
611 session->gpsdata.satellites_used);
612 break;
613 case GARMIN_PKTID_PROTOCOL_ARRAY:
614 // Pid_Protocol_Array, ID 253
615 // this packet is never requested, it just comes, in some case
616 // after a GARMIN_PKTID_PRODUCT_RQST
617 GPSD_LOG(LOG_INF, &session->context->errout,
618 "Garmin: Appl, Product Capability, sz: %d\n",
619 pkt_len);
620 for (i = 0; i < pkt_len; i += 3) {
621 GPSD_LOG(LOG_INF, &session->context->errout,
622 "Garmin: %c%03d\n",
623 buf[i], get_uint16((uint8_t *) & buf[i + 1]));
624 }
625 break;
626 default:
627 GPSD_LOG(LOG_WARN, &session->context->errout,
628 "Garmin: Unknown packet id: %#02x, Sz: %#02x\n",
629 pkt_id, pkt_len);
630 break;
631 }
632 GPSD_LOG(LOG_DATA, &session->context->errout,
633 "Garmin: PrintSERPacket(, %#02x, %#02x, ) mask=(%s)\n",
634 pkt_id, pkt_len, gps_maskdump(mask));
635 return mask;
636 }
637
638
639 #if defined(HAVE_LIBUSB) && defined(__linux__)
640 // This works around cppcheck not looking into enough config branches
641 // cppcheck-suppress unusedFunction
PrintUSBPacket(struct gps_device_t * session,Packet_t * pkt)642 static gps_mask_t PrintUSBPacket(struct gps_device_t *session, Packet_t * pkt)
643 /* For debugging, decodes and prints some known packets */
644 {
645 gps_mask_t mask = 0;
646 int maj_ver;
647 int min_ver;
648 uint32_t mode = 0;
649 uint16_t prod_id = 0;
650 uint32_t veri = 0;
651 uint32_t serial;
652 uint32_t mDataSize = get_int32((uint8_t *) & pkt->mDataSize);
653 uint8_t *buffer = (uint8_t *) pkt;
654
655 GPSD_LOG(LOG_PROG, &session->context->errout, "Garmin: PrintUSBPacket()\n");
656 if (DLE == pkt->mPacketType) {
657 GPSD_LOG(LOG_PROG, &session->context->errout,
658 "Garmin: really a SER packet!\n");
659 return PrintSERPacket(session,
660 (unsigned char)buffer[1],
661 (int)buffer[2], (unsigned char *)(buffer + 3));
662 }
663
664 if (4096 < mDataSize) {
665 GPSD_LOG(LOG_WARN, &session->context->errout,
666 "Garmin: bogus packet, size too large=%d\n",
667 mDataSize);
668 return 0;
669 }
670
671 switch (pkt->mPacketType) {
672 case GARMIN_LAYERID_TRANSPORT:
673 /* Garmin USB layer specific */
674 switch (pkt->mPacketId) {
675 case GARMIN_PKTID_TRANSPORT_START_SESSION_REQ:
676 // Pid_Start_Session, ID 5
677 GPSD_LOG(LOG_PROG, &session->context->errout,
678 "Garmin: Transport, Start Session req\n");
679 break;
680 case GARMIN_PKTID_TRANSPORT_START_SESSION_RESP:
681 // Pid_Session_Started, ID 6
682 mode = get_int32(&pkt->mData.uchars[0]);
683 GPSD_LOG(LOG_PROG, &session->context->errout,
684 "Garmin: Transport, Start Session resp, unit: 0x%x\n",
685 mode);
686 break;
687 default:
688 GPSD_LOG(LOG_PROG, &session->context->errout,
689 "Garmin: Transport, Packet: Type %d %d %d, ID: %d,"
690 "Sz: %d\n",
691 pkt->mPacketType, pkt->mReserved1, pkt->mReserved2,
692 pkt->mPacketId, mDataSize);
693 break;
694 }
695 break;
696 case GARMIN_LAYERID_APPL:
697 /* raw data transport, shared with Garmin Serial Driver */
698
699 mask = PrintSERPacket(session,
700 (unsigned char)pkt->mPacketId,
701 (int)mDataSize,
702 (unsigned char *)pkt->mData.uchars);
703 break;
704 case 75:
705 // private, garmin USB kernel driver specific
706 switch (pkt->mPacketId) {
707 case PRIV_PKTID_SET_MODE:
708 prod_id = get_uint16(&pkt->mData.uchars[0]);
709 GPSD_LOG(LOG_PROG, &session->context->errout,
710 "Garmin: Private, Set Mode: %d\n", prod_id);
711 break;
712 case PRIV_PKTID_INFO_REQ:
713 GPSD_LOG(LOG_PROG, &session->context->errout,
714 "Garmin: Private, ID: Info Req\n");
715 break;
716 case PRIV_PKTID_INFO_RESP:
717 veri = get_int32(pkt->mData.uchars);
718 maj_ver = (int)(veri >> 16);
719 min_ver = (int)(veri & 0xffff);
720 mode = get_int32(&pkt->mData.uchars[4]);
721 serial = get_int32(&pkt->mData.uchars[8]);
722 GPSD_LOG(LOG_PROG, &session->context->errout,
723 "Garmin: Private, ID: Info Resp\n");
724 GPSD_LOG(LOG_INF, &session->context->errout,
725 "Garmin: USB Driver found, Version %d.%d, Mode: %d, GPS Serial# %u\n",
726 maj_ver, min_ver, mode, serial);
727 break;
728 default:
729 GPSD_LOG(LOG_PROG, &session->context->errout,
730 "Garmin: Private, Packet: ID: %d, Sz: %d\n",
731 pkt->mPacketId, mDataSize);
732 break;
733 }
734 break;
735 default:
736 GPSD_LOG(LOG_PROG, &session->context->errout,
737 "Garmin: Packet: Type %d %d %d, ID: %d, Sz: %d\n",
738 pkt->mPacketType, pkt->mReserved1, pkt->mReserved2,
739 pkt->mPacketId, mDataSize);
740 break;
741 }
742
743 return mask;
744 }
745
746 #endif /* HAVE_LIBUSB */
747
748
749 #if defined(HAVE_LIBUSB) && defined(__linux__)
750 /* build and send a packet w/ USB protocol */
Build_Send_USB_Packet(struct gps_device_t * session,uint32_t layer_id,uint32_t pkt_id,uint32_t length,uint32_t data)751 static void Build_Send_USB_Packet(struct gps_device_t *session,
752 uint32_t layer_id, uint32_t pkt_id,
753 uint32_t length, uint32_t data)
754 {
755 uint8_t *buffer = (uint8_t *) session->driver.garmin.Buffer;
756 Packet_t *thePacket = (Packet_t *) buffer;
757 ssize_t theBytesReturned = 0;
758 ssize_t theBytesToWrite = 12 + (ssize_t) length;
759
760 set_int32(buffer, layer_id);
761 set_int32(buffer + 4, pkt_id);
762 set_int32(buffer + 8, length);
763 if (2 == length) {
764 set_int16(buffer + 12, data);
765 } else if (4 == length) {
766 set_int32(buffer + 12, data);
767 }
768 (void)PrintUSBPacket(session, thePacket);
769
770 theBytesReturned = gpsd_write(session, (const char *)thePacket,
771 (size_t) theBytesToWrite);
772 GPSD_LOG(LOG_PROG, &session->context->errout,
773 "Garmin: SendPacket(), wrote %zd bytes\n",
774 theBytesReturned);
775
776 // Garmin says:
777 // If the packet size was an exact multiple of the USB packet
778 // size, we must make a final write call with no data
779
780 // as a practical matter no known packets are 64 bytes long so
781 // this is untested
782
783 // So here goes just in case
784 if (0 == (theBytesToWrite % ASYNC_DATA_SIZE)) {
785 char *n = "";
786 (void)gpsd_write(session, n, 0);
787 }
788 }
789 #endif /* HAVE_LIBUSB && __linux__ */
790
791 /* build and send a packet in serial protocol */
792 /* layer_id unused */
793 // FIX-ME: This should go through the common message buffer someday
Build_Send_SER_Packet(struct gps_device_t * session,uint32_t layer_id UNUSED,uint32_t pkt_id,uint32_t length,uint32_t data)794 static void Build_Send_SER_Packet(struct gps_device_t *session,
795 uint32_t layer_id UNUSED, uint32_t pkt_id,
796 uint32_t length, uint32_t data)
797 {
798 uint8_t *buffer = (uint8_t *) session->driver.garmin.Buffer;
799 uint8_t *buffer0 = buffer;
800 Packet_t *thePacket = (Packet_t *) buffer;
801 ssize_t theBytesReturned = 0;
802 ssize_t theBytesToWrite = 6 + (ssize_t) length;
803 uint8_t chksum = 0;
804
805 *buffer++ = (uint8_t) DLE;
806 *buffer++ = (uint8_t) pkt_id;
807 chksum = pkt_id;
808 *buffer++ = (uint8_t) length;
809 chksum += length;
810 /* ??? What is this doing? */
811 if (2 == length) {
812 /* carefull! no DLE stuffing here! */
813 set_int16(buffer, data);
814 chksum += buffer[0];
815 chksum += buffer[1];
816 } else if (4 == length) {
817 /* carefull! no DLE stuffing here! */
818 set_int32(buffer, data);
819 chksum += buffer[0];
820 chksum += buffer[1];
821 chksum += buffer[2];
822 chksum += buffer[3];
823 }
824 /* ??? How is data copied to the buffer? */
825 buffer += length;
826
827 // Add checksum
828 *buffer++ = -chksum;
829 if (DLE == -chksum) {
830 /* stuff another DLE */
831 *buffer++ = (uint8_t) DLE;
832 theBytesToWrite++;
833 }
834 // Add DLE, ETX
835 *buffer++ = (uint8_t) DLE;
836 /* we used to say n++ here, but scan-build complains */
837 *buffer = (uint8_t) ETX;
838
839 (void)PrintSERPacket(session,
840 (unsigned char)buffer0[1],
841 (int)buffer0[2], (unsigned char *)(buffer0 + 3));
842
843 theBytesReturned = gpsd_write(session, (const char *)thePacket,
844 (size_t) theBytesToWrite);
845 GPSD_LOG(LOG_PROG, &session->context->errout,
846 "Garmin: SendPacket(), wrote %zd bytes\n",
847 theBytesReturned);
848
849 }
850
851 #if defined(HAVE_LIBUSB) && defined(__linux__)
852 /*
853 * is_usb_device() - is a specified device USB matching given vendor/product?
854 *
855 * BUG: Doesn't actually match against path yet. Must finish this function
856 * by querying /sys/dev/char, either directly or using libudev. Greg KH
857 * assures this is possible, though he is vague about how.
858 *
859 * libudev: http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
860 */
861 // This works around cppcheck not looking into enough config branches
862 // cppcheck-suppress unusedFunction
is_usb_device(const char * path UNUSED,int vendor,int product,struct gpsd_errout_t * errout)863 static bool is_usb_device(const char *path UNUSED, int vendor, int product,
864 struct gpsd_errout_t *errout)
865 {
866 // discover devices
867 libusb_device **list;
868 ssize_t cnt;
869 ssize_t i = 0;
870 bool found = false;
871
872 GPSD_LOG(LOG_INF, errout, "attempting USB device enumeration.\n");
873 (void)libusb_init(NULL);
874
875 if ((cnt = libusb_get_device_list(NULL, &list)) < 0) {
876 GPSD_LOG(LOG_ERROR, errout, "USB device list call failed.\n");
877 libusb_exit(NULL);
878 return false;
879 }
880
881 for (i = 0; i < cnt; i++) {
882 struct libusb_device_descriptor desc;
883 libusb_device *dev = list[i];
884
885 int r = libusb_get_device_descriptor(dev, &desc);
886 if (r < 0) {
887 GPSD_LOG(LOG_ERROR, errout,
888 "USB descriptor fetch failed on device %zd.\n", i);
889 continue;
890 }
891
892 /* we can extract device descriptor data */
893 GPSD_LOG(LOG_INF, errout,
894 "%04x:%04x (bus %d, device %d)\n",
895 desc.idVendor, desc.idProduct,
896 libusb_get_bus_number(dev),
897 libusb_get_device_address(dev));
898
899 /* we match if vendor and product ID are right */
900 if (desc.idVendor == (uint16_t)vendor && desc.idProduct == (uint16_t)product) {
901 found = true;
902 break;
903 }
904 }
905
906 GPSD_LOG(LOG_INF, errout,
907 "vendor/product match with %04x:%04x %sfound\n",
908 vendor, product, found ? "" : "not ");
909 libusb_free_device_list(list, 1);
910 libusb_exit(NULL);
911 return found;
912 }
913
914 #endif /* HAVE_LIBUSB */
915
916 /*
917 * garmin_usb_detect() - detect a Garmin USB device connected to session fd.
918 *
919 * This is ONLY for USB devices reporting as: 091e:0003.
920 *
921 * This driver ONLY works in Linux and ONLY when the garmin_gps kernel
922 * module is installed.
923 *
924 * This is only necessary because under Linux Garmin USB devices need a
925 * kernel module rather than being normal USB-serial devices.
926 *
927 * The actual wire protocol from the Garmin device is very strange. There
928 * are no delimiters. End of packet is signaled by a zero-length read
929 * on the USB device, and start of packet is the next read. You can't just
930 * ignore the zero reads and pass the data through - you'd never be able
931 * to tell where the packet boundaries are.
932 *
933 * The garmin_usb module's job is to grab the packet and frame it in
934 * DLEs (with DLE stuffing). This makes the USB packets look as
935 * though they came from a regular Garmin *serial* device, which is how
936 * most of the processing for both types can be unified here.
937 *
938 * return 1 is device found
939 * return 0 if not
940 */
garmin_usb_detect(struct gps_device_t * session UNUSED)941 static bool garmin_usb_detect(struct gps_device_t *session UNUSED)
942 {
943 #if defined(__linux__)
944 /*
945 * Only perform this check if we're looking at a USB-serial
946 * device. This prevents drivers for attached serial GPSes
947 * fronm being rudely elbowed aside by this one if they happen
948 * to be trying to coexist with the Garmin.
949 */
950 if (session->sourcetype != source_usb)
951 return false;
952 else {
953 #ifdef HAVE_LIBUSB
954 if (!is_usb_device(session->gpsdata.dev.path, 0x091e, 0x0003,
955 &session->context->errout))
956 return false;
957
958 if (!gpsd_set_raw(session)) {
959 GPSD_LOG(LOG_ERROR, &session->context->errout,
960 "Garmin: garmin_usb_detect: error changing port attributes: %s\n",
961 strerror(errno));
962 return false;
963 }
964
965 if (sizeof(session->driver.garmin.Buffer) < sizeof(Packet_t)) {
966 /* dunno how this happens, but it does on some compilers */
967 GPSD_LOG(LOG_ERROR, &session->context->errout,
968 "Garmin: garmin_usb_detect: Compile error, garmin.Buffer too small.\n");
969 return false;
970 }
971
972 // FIXME!!! needs to use libusb totally and move garmin_gps aside */
973 // set Mode 1, mode 0 is broken somewhere past 2.6.14
974 // but how?
975 GPSD_LOG(LOG_PROG, &session->context->errout,
976 "Garmin: Set garmin_gps driver mode = 0\n");
977 Build_Send_USB_Packet(session, GARMIN_LAYERID_PRIVATE,
978 PRIV_PKTID_SET_MODE, 4, MODE_GARMIN_SERIAL);
979 // expect no return packet !?
980
981 return true;
982 #else
983 return false;
984 #endif /* HAVE_LIBUSB */
985 }
986 #else
987 return false;
988 #endif /* __linux__ */
989 }
990
garmin_event_hook(struct gps_device_t * session,event_t event)991 static void garmin_event_hook(struct gps_device_t *session, event_t event)
992 {
993 if (session->context->readonly)
994 return;
995 /*
996 * FIX-ME: It might not be necessary to call this on reactivate.
997 * Experiment to see if the holds its settings through a close.
998 */
999 if (event == event_identified || event == event_reactivate) {
1000 // Tell the device to send product data
1001 GPSD_LOG(LOG_PROG, &session->context->errout,
1002 "Garmin: Get Product Data\n");
1003 Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL,
1004 GARMIN_PKTID_PRODUCT_RQST, 0, 0);
1005
1006 // turn on PVT data 49
1007 GPSD_LOG(LOG_PROG, &session->context->errout,
1008 "Garmin: Set to send reports every 1 second\n");
1009
1010 Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL,
1011 GARMIN_PKTID_L001_COMMAND_DATA, 2,
1012 CMND_START_PVT_DATA);
1013
1014 #if USE_RMD
1015 // turn on RMD data 110
1016 GPSD_LOG(LOG_PROG, &session->context->errout,
1017 "Garmin: Set to send Raw sat data\n");
1018 Build_Send_SER_Packet(session, GARMIN_LAYERID_APPL,
1019 GARMIN_PKTID_L001_COMMAND_DATA, 2,
1020 CMND_START_RM_DATA);
1021 #endif
1022 }
1023 if (event == event_deactivate)
1024 /* FIX-ME: is any action needed, or is closing the port sufficient? */
1025 GPSD_LOG(LOG_PROG, &session->context->errout,
1026 "Garmin: garmin_close()\n");
1027 }
1028
1029 #define Send_ACK() Build_Send_SER_Packet(session, 0, ACK, 0, 0)
1030 #define Send_NAK() Build_Send_SER_Packet(session, 0, NAK, 0, 0)
1031
garmin_ser_parse(struct gps_device_t * session)1032 gps_mask_t garmin_ser_parse(struct gps_device_t *session)
1033 {
1034 unsigned char *buf = session->lexer.outbuffer;
1035 size_t len = session->lexer.outbuflen;
1036 unsigned char data_buf[MAX_BUFFER_SIZE];
1037 unsigned char c;
1038 int i = 0;
1039 size_t n = 0;
1040 int data_index = 0;
1041 int got_dle = 0;
1042 unsigned char pkt_id = 0;
1043 unsigned char pkt_len = 0;
1044 unsigned char chksum = 0;
1045 gps_mask_t mask = 0;
1046 struct timespec delay;
1047
1048 GPSD_LOG(LOG_RAW, &session->context->errout,
1049 "Garmin: garmin_ser_parse()\n");
1050 if (6 > len) {
1051 /* WTF? */
1052 /* minimum packet; <DLE> [pkt id] [length=0] [chksum] <DLE> <STX> */
1053 Send_NAK();
1054 GPSD_LOG(LOG_RAW, &session->context->errout,
1055 "Garmin: serial too short: %zd\n", len);
1056 return 0;
1057 }
1058 /* debug */
1059 for (i = 0; i < (int)len; i++) {
1060 GPSD_LOG(LOG_RAW, &session->context->errout,
1061 "Garmin: Char: %#02x\n", buf[i]);
1062 }
1063
1064 if ('\x10' != buf[0]) {
1065 Send_NAK();
1066 GPSD_LOG(LOG_RAW, &session->context->errout,
1067 "Garmin: buf[0] not DLE\n");
1068 return 0;
1069 }
1070 n = 1;
1071 pkt_id = buf[n++];
1072 chksum = pkt_id;
1073 if ('\x10' == pkt_id) {
1074 if ('\x10' != buf[n++]) {
1075 Send_NAK();
1076 GPSD_LOG(LOG_RAW, &session->context->errout,
1077 "Garmin: Bad pkt_id %#02x\n", pkt_id);
1078 return 0;
1079 }
1080 }
1081
1082 pkt_len = buf[n++];
1083 chksum += pkt_len;
1084 if ('\x10' == pkt_len) {
1085 if ('\x10' != buf[n++]) {
1086 GPSD_LOG(LOG_RAW, &session->context->errout,
1087 "Garmin: Bad pkt_len %#02x\n", pkt_len);
1088 Send_NAK();
1089 return 0;
1090 }
1091 }
1092 data_index = 0;
1093 for (i = 0; i < 256; i++) {
1094
1095 if ((int)pkt_len == data_index) {
1096 // got it all
1097 break;
1098 }
1099 if (len < n + i) {
1100 GPSD_LOG(LOG_RAW, &session->context->errout,
1101 "Garmin: Packet too short %zd < %zd\n",
1102 len, n + i);
1103 Send_NAK();
1104 return 0;
1105 }
1106 c = buf[n + i];
1107 if (got_dle) {
1108 got_dle = 0;
1109 if ('\x10' != c) {
1110 Send_NAK();
1111 GPSD_LOG(LOG_RAW, &session->context->errout,
1112 "Garmin: Bad DLE %#02x\n", c);
1113 return 0;
1114 }
1115 } else {
1116 chksum += c;
1117 data_buf[data_index++] = c;
1118 if ('\x10' == c) {
1119 got_dle = 1;
1120 }
1121 }
1122 }
1123 /* get checksum */
1124 if (len < n + i) {
1125 Send_NAK();
1126 GPSD_LOG(LOG_RAW, &session->context->errout,
1127 "Garmin: No checksum, Packet too short %zd < %zd\n", len,
1128 n + i);
1129 return 0;
1130 }
1131 c = buf[n + i++];
1132 chksum += c;
1133 /* get final DLE */
1134 if (len < n + i) {
1135 Send_NAK();
1136 GPSD_LOG(LOG_RAW, &session->context->errout,
1137 "Garmin: No final DLE, Packet too short %zd < %zd\n", len,
1138 n + i);
1139 return 0;
1140 }
1141 c = buf[n + i++];
1142 if ('\x10' != c) {
1143 Send_NAK();
1144 GPSD_LOG(LOG_RAW, &session->context->errout,
1145 "Garmin: Final DLE not DLE\n");
1146 return 0;
1147 }
1148 /* get final ETX */
1149 if (len < n + i) {
1150 Send_NAK();
1151 GPSD_LOG(LOG_RAW, &session->context->errout,
1152 "Garmin: No final ETX, Packet too short %zd < %zd\n", len,
1153 n + i);
1154 return 0;
1155 }
1156 /* we used to say n++ here, but scan-build complains */
1157 c = buf[n + i];
1158 if ('\x03' != c) {
1159 Send_NAK();
1160 GPSD_LOG(LOG_RAW, &session->context->errout,
1161 "Garmin: Final ETX not ETX\n");
1162 return 0;
1163 }
1164
1165 /* debug */
1166 for (i = 0; i < data_index; i++) {
1167 GPSD_LOG(LOG_RAW, &session->context->errout,
1168 "Garmin: Char: %#02x\n", data_buf[i]);
1169 }
1170
1171
1172 GPSD_LOG(LOG_DATA, &session->context->errout,
1173 "Garmin: garmin_ser_parse() Type: %#02x, Len: %#02x, chksum: %#02x\n",
1174 pkt_id, pkt_len, chksum);
1175 mask = PrintSERPacket(session, pkt_id, pkt_len, data_buf);
1176
1177 // sending ACK too soon might hang the session
1178 // so send ACK last, after a pause
1179 /* wait 300 uSec */
1180 delay.tv_sec = 0;
1181 delay.tv_nsec = 300000L;
1182 nanosleep(&delay, NULL);
1183
1184 Send_ACK();
1185 GPSD_LOG(LOG_DATA, &session->context->errout,
1186 "Garmin: garmin_ser_parse( )\n");
1187 return mask;
1188 }
1189
1190
1191 #ifdef RECONFIGURE_ENABLE
settle(void)1192 static void settle(void)
1193 {
1194 struct timespec delay, rem;
1195 memset(&delay, 0, sizeof(delay));
1196 delay.tv_sec = 0;
1197 delay.tv_nsec = 333000000L;
1198 nanosleep(&delay, &rem);
1199 }
1200
garmin_switcher(struct gps_device_t * session,int mode)1201 static void garmin_switcher(struct gps_device_t *session, int mode)
1202 {
1203 if (mode == MODE_NMEA) {
1204 const unsigned char switcher[] =
1205 { 0x10, 0x0A, 0x02, 0x26, 0x00, 0xCE, 0x10, 0x03 };
1206 // Note hard-coded string length in the next line...
1207 ssize_t status = gpsd_write(session, (char *)switcher,
1208 sizeof(switcher));
1209 if (status == (ssize_t)sizeof(switcher)) {
1210 GPSD_LOG(LOG_PROG, &session->context->errout,
1211 "Garmin: => GPS: turn off binary %02x %02x %02x... \n",
1212 switcher[0], switcher[1], switcher[2]);
1213 } else {
1214 GPSD_LOG(LOG_ERROR, &session->context->errout,
1215 "Garmin: => GPS: FAILED\n");
1216 }
1217 settle(); // wait 333mS, essential!
1218
1219 /* once a sec, no binary, no averaging, NMEA 2.3, WAAS */
1220 (void)nmea_send(session, "$PGRMC1,1,1");
1221 //(void)nmea_send(fd, "$PGRMC1,1,1,1,,,,2,W,N");
1222 (void)nmea_send(session, "$PGRMI,,,,,,,R");
1223 settle(); // wait 333mS, essential!
1224 } else {
1225 (void)nmea_send(session, "$PGRMC1,1,2,1,,,,2,W,N");
1226 (void)nmea_send(session, "$PGRMI,,,,,,,R");
1227 settle(); // wait 333mS, essential!
1228 }
1229 }
1230 #endif /* RECONFIGURE_ENABLE */
1231
1232 #ifdef CONTROLSEND_ENABLE
garmin_control_send(struct gps_device_t * session,char * buf,size_t buflen)1233 static ssize_t garmin_control_send(struct gps_device_t *session,
1234 char *buf, size_t buflen)
1235 /* not used by the daemon, it's for gpsctl and friends */
1236 {
1237 session->msgbuflen = buflen;
1238 (void)memcpy(session->msgbuf, buf, buflen);
1239 return gpsd_write(session, session->msgbuf, session->msgbuflen);
1240 }
1241 #endif /* CONTROLSEND_ENABLE */
1242
garmin_time_offset(struct gps_device_t * session)1243 static double garmin_time_offset(struct gps_device_t *session)
1244 {
1245 if (session->sourcetype == source_usb) {
1246 return 0.035; /* Garmin USB, expect +/- 40mS jitter */
1247 }
1248 /* only two sentences ships time */
1249 /* but the PVT data is always first */
1250 switch (session->gpsdata.dev.baudrate) {
1251 case 4800:
1252 return 0.430; /* TBD */
1253 case 9600:
1254 return 0.430; /* tested 12Arp10 */
1255 case 19200:
1256 return 0.430; /* TBD */
1257 case 38400:
1258 return 0.430; /* TBD */
1259 }
1260 return 0.430; /* WTF? WAG */
1261 }
1262
1263 /* this is everything we export */
1264
1265 /* *INDENT-OFF* */
1266 const struct gps_type_t driver_garmin_usb_binary =
1267 {
1268 .type_name = "Garmin USB binary", /* full name of type */
1269 .packet_type = GARMIN_PACKET, /* associated lexer packet type */
1270 .flags = DRIVER_STICKY, /* remember this */
1271 .trigger = NULL, /* no trigger, it has a probe */
1272 .channels = GARMIN_CHANNELS, /* consumer-grade GPS */
1273 .probe_detect = garmin_usb_detect,/* how to detect at startup time */
1274 .get_packet = generic_get, /* how to grab a packet */
1275 .parse_packet = garmin_ser_parse, /* parse message packets */
1276 .rtcm_writer = NULL, /* don't send DGPS corrections */
1277 .init_query = NULL, /* non-perturbing initial query */
1278 .event_hook = garmin_event_hook,/* lifetime ebent handler */
1279 #ifdef RECONFIGURE_ENABLE
1280 .speed_switcher = NULL, /* no speed switcher */
1281 .mode_switcher = NULL, /* Garmin USB Binary has no NMEA */
1282 .rate_switcher = NULL, /* no sample-rate switcher */
1283 .min_cycle.tv_sec = 0,
1284 .min_cycle.tv_nsec = 10000000, /* 10Hz */
1285 #endif /* RECONFIGURE_ENABLE */
1286 #ifdef CONTROLSEND_ENABLE
1287 .control_send = garmin_control_send, /* send raw bytes */
1288 #endif /* CONTROLSEND_ENABLE */
1289 .time_offset = garmin_time_offset,
1290 };
1291 /* *INDENT-ON* */
1292
1293 /* *INDENT-OFF* */
1294 const struct gps_type_t driver_garmin_ser_binary =
1295 {
1296 .type_name = "Garmin Serial binary", /* full name of type */
1297 .packet_type = GARMIN_PACKET, /* associated lexer packet type */
1298 .flags = DRIVER_STICKY, /* remember this */
1299 .trigger = NULL, /* no trigger, it has a probe */
1300 .channels = GARMIN_CHANNELS, /* consumer-grade GPS */
1301 .probe_detect = NULL, /* how to detect at startup time */
1302 .get_packet = generic_get, /* how to grab a packet */
1303 .parse_packet = garmin_ser_parse, /* parse message packets */
1304 .rtcm_writer = NULL, /* don't send DGPS corrections */
1305 .init_query = NULL, /* non-perturbing initial query */
1306 .event_hook = NULL, /* lifetime event handler */
1307 #ifdef RECONFIGURE_ENABLE
1308 .speed_switcher = NULL, /* no speed switcher */
1309 .mode_switcher = garmin_switcher, /* how to change modes */
1310 .rate_switcher = NULL, /* no sample-rate switcher */
1311 .min_cycle.tv_sec = 0,
1312 .min_cycle.tv_nsec = 10000000, /* 10Hz */
1313 #endif /* RECONFIGURE_ENABLE */
1314 #ifdef CONTROLSEND_ENABLE
1315 .control_send = garmin_control_send, /* send raw bytes */
1316 #endif /* CONTROLSEND_ENABLE */
1317 .time_offset = garmin_time_offset,
1318 };
1319 /* *INDENT-ON* */
1320
1321 #endif /* GARMIN_ENABLE */
1322
1323 // vim: set expandtab shiftwidth=4
1324