1 /*
2 * This is the gpsd driver for GeoStar Navigation receivers
3 * operating in binary mode.
4 *
5 * Tested with GeoS-1M GPS/GLONASS receiver.
6 *
7 * By Viktar Palstsiuk, viktar.palstsiuk@promwad.com
8 *
9 * This file is Copyright (c) 2010-2019 by the GPSD project
10 * SPDX-License-Identifier: BSD-2-clause
11 */
12
13 #include "gpsd_config.h" /* must be before all includes */
14
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <math.h>
18 #include <string.h>
19
20 #include "gpsd.h"
21 #include "bits.h"
22 #include "strfuncs.h"
23 #include "timespec.h"
24
25 #ifdef GEOSTAR_ENABLE
26 #define GEOSTAR_CHANNELS 24
27
28 #define JAN_2008 0x47798280 /* 1199145600 = 2008 - 1970 in seconds */
29
30 #define OFFSET(n) ((n)*4+4)
31
decode_channel_id(uint32_t ch_id)32 static int decode_channel_id (uint32_t ch_id) {
33 int num = 0;
34 num = (int)(ch_id & 0x1F); /* SV ID */
35 if((ch_id & (1<<30)) == 0) num += GLONASS_PRN_OFFSET; /* GLONASS SV */
36 else if (num == 0 ) num = 32; /* GPS SV */
37 return num;
38 }
39
geostar_write(struct gps_device_t * session,unsigned int id,unsigned char * data,size_t len)40 static int geostar_write(struct gps_device_t *session,
41 unsigned int id, unsigned char *data, size_t len)
42 {
43 int i;
44 unsigned long cs = 0;
45
46 putbyte(session->msgbuf, 0, 'P');
47 putbyte(session->msgbuf, 1, 'S');
48 putbyte(session->msgbuf, 2, 'G');
49 putbyte(session->msgbuf, 3, 'G');
50
51 putbe16(session->msgbuf, 4, id);
52 putbe16(session->msgbuf, 6, len);
53
54 /* Copy content */
55 memcpy(session->msgbuf + 8, data, len * 4);
56
57 len += 2; /* PSGG + id + len */
58
59 /* Calculate checksum */
60 for (i = 0; (size_t)i < len; i++) {
61 cs ^= getleu32(session->msgbuf, i * 4);
62 }
63
64 putle32(session->msgbuf, len * 4, cs);
65
66 len += 1; /* Checksum */
67
68 session->msgbuflen = len * 4;
69
70 GPSD_LOG(LOG_PROG, &session->context->errout,
71 "Sent GeoStar packet id 0x%x\n", id);
72 if (gpsd_write(session, session->msgbuf, session->msgbuflen) !=
73 (ssize_t) session->msgbuflen)
74 return -1;
75
76 return 0;
77 }
78
79 /* geostar_detect()
80 *
81 * see if it looks like a GeoStar device is listening and
82 * return 1 if found, 0 if not
83 */
geostar_detect(struct gps_device_t * session)84 static bool geostar_detect(struct gps_device_t *session)
85 {
86 unsigned char buf[1 * 4];
87 bool ret = false;
88 int myfd;
89
90 myfd = session->gpsdata.gps_fd;
91
92 /* request firmware revision and look for a valid response */
93 putbe32(buf, 0, 0);
94 if (geostar_write(session, 0xc1, buf, 1) == 0) {
95 unsigned int n;
96 for (n = 0; n < 3; n++) {
97 if (!nanowait(myfd, NS_IN_SEC))
98 break;
99 if (generic_get(session) >= 0) {
100 if (session->lexer.type == GEOSTAR_PACKET) {
101 GPSD_LOG(LOG_RAW, &session->context->errout,
102 "geostar_detect found\n");
103 ret = true;
104 break;
105 }
106 }
107 }
108 }
109
110 return ret;
111 }
112
geostar_analyze(struct gps_device_t * session)113 static gps_mask_t geostar_analyze(struct gps_device_t *session)
114 {
115 int i, len;
116 gps_mask_t mask = 0;
117 unsigned int id;
118 uint16_t uw1, uw2;
119 uint32_t ul1, ul2, ul3, ul4, ul5;
120 double d1, d2, d3, d4, d5;
121 char buf[BUFSIZ];
122 char buf2[BUFSIZ];
123
124 if (session->lexer.type != GEOSTAR_PACKET) {
125 GPSD_LOG(LOG_INF, &session->context->errout,
126 "geostar_analyze packet type %d\n",
127 session->lexer.type);
128 return 0;
129 }
130
131 if (session->lexer.outbuflen < 12 || session->lexer.outbuffer[0] != 'P')
132 return 0;
133
134 /* put data part of message in buf */
135
136 memset(buf, 0, sizeof(buf));
137 /* cppcheck-suppress redundantCopy */
138 memcpy(buf, session->lexer.outbuffer, session->lexer.outbuflen);
139
140 buf2[len = 0] = '\0';
141 for (i = 0; i < (int)session->lexer.outbuflen; i++) {
142 str_appendf(buf2, sizeof(buf2),
143 "%02x", buf[len++] = session->lexer.outbuffer[i]);
144 }
145
146 id = (unsigned int)getleu16(session->lexer.outbuffer, OFFSET(0));
147
148 GPSD_LOG(LOG_DATA, &session->context->errout,
149 "GeoStar packet id 0x%02x length %d: %s\n", id, len, buf2);
150
151 session->cycle_end_reliable = true;
152
153 switch (id) {
154 case 0x10:
155 GPSD_LOG(LOG_INF, &session->context->errout, "Raw measurements\n");
156 break;
157 case 0x11:
158 GPSD_LOG(LOG_INF, &session->context->errout, "GPS sub-frame data\n");
159 break;
160 case 0x12:
161 GPSD_LOG(LOG_INF, &session->context->errout, "GLONASS sub-frame data\n");
162 break;
163 case 0x13:
164 d1 = getled64(buf, OFFSET(1));
165 d2 = getled64(buf, OFFSET(3));
166 d3 = getled64(buf, OFFSET(5));
167 d4 = getled64(buf, OFFSET(29)); /* GPS time */
168 d5 = getled64(buf, OFFSET(31)); /* GLONASS time */
169 GPSD_LOG(LOG_INF, &session->context->errout,
170 "ECEF coordinates %g %g %g %f %f\n", d1, d2, d3, d4, d5);
171 break;
172 case 0x20:
173 d1 = getled64(buf, OFFSET(1)); /* time */
174
175 DTOTS(&session->newdata.time, d1);
176 session->newdata.time.tv_sec += JAN_2008;
177
178 session->newdata.latitude = getled64(buf, OFFSET(3)) * RAD_2_DEG;
179 session->newdata.longitude = getled64(buf, OFFSET(5)) * RAD_2_DEG;
180 /* altitude above ellipsoid */
181 session->newdata.altHAE = getled64(buf, OFFSET(7));
182 session->newdata.geoid_sep = getled64(buf, OFFSET(9));
183 session->gpsdata.satellites_used = (int)getles32(buf, OFFSET(11));
184 session->gpsdata.dop.gdop = getled64(buf, OFFSET(13));
185 session->gpsdata.dop.pdop = getled64(buf, OFFSET(15));
186 session->gpsdata.dop.tdop = getled64(buf, OFFSET(17));
187 session->gpsdata.dop.hdop = getled64(buf, OFFSET(19));
188 session->gpsdata.dop.vdop = getled64(buf, OFFSET(21));
189 session->newdata.speed = getled64(buf, OFFSET(31));
190 session->newdata.track = getled64(buf, OFFSET(33)) * RAD_2_DEG;
191
192 ul1 = getleu32(buf, OFFSET(29)); /* status */
193
194 if (ul1 != 0) {
195 session->gpsdata.status = STATUS_NO_FIX;
196 mask |= STATUS_SET;
197 } else {
198 if (session->gpsdata.status < STATUS_FIX) {
199 session->gpsdata.status = STATUS_FIX;
200 mask |= STATUS_SET;
201 }
202 }
203 mask |= TIME_SET | NTPTIME_IS | LATLON_SET | ALTITUDE_SET |
204 SPEED_SET | TRACK_SET | DOP_SET | USED_IS | REPORT_IS;
205
206 GPSD_LOG(LOG_INF, &session->context->errout,
207 "Geographic coordinates %f %g %g %g %g %g\n",
208 d1,
209 session->newdata.latitude,
210 session->newdata.longitude,
211 session->newdata.altHAE,
212 session->newdata.speed,
213 session->newdata.track);
214 GPSD_LOG(LOG_INF, &session->context->errout,
215 "Dilution of precision %g %g %g %g %g\n",
216 session->gpsdata.dop.gdop,
217 session->gpsdata.dop.pdop,
218 session->gpsdata.dop.tdop,
219 session->gpsdata.dop.hdop,
220 session->gpsdata.dop.vdop);
221 break;
222 case 0x21:
223 ul1 = getleu32(buf, OFFSET(1));
224 ul2 = getleu32(buf, OFFSET(2));
225 uw1 = getleu16(buf, OFFSET(3));
226 uw2 = getleu16(buf, OFFSET(3) + 2);
227 GPSD_LOG(LOG_INF, &session->context->errout,
228 "Current receiver telemetry %x %d %d %d\n",
229 ul1, ul2, uw1, uw2);
230 if(ul1 & (1<<3)) {
231 session->newdata.mode = MODE_2D;
232 }
233 else {
234 session->newdata.mode = MODE_3D;
235 }
236 if(ul1 & (1<<2)) {
237 session->gpsdata.status = STATUS_FIX;
238 }
239 else {
240 session->gpsdata.status = STATUS_NO_FIX;
241 session->newdata.mode = MODE_NO_FIX;
242 }
243
244 mask |= MODE_SET | STATUS_SET;
245 break;
246 case 0x22:
247 ul1 = getleu32(buf, OFFSET(1));
248 GPSD_LOG(LOG_INF, &session->context->errout, "SVs in view %d\n", ul1);
249 session->gpsdata.satellites_visible = (int)ul1;
250 if(ul1 > GEOSTAR_CHANNELS) ul1 = GEOSTAR_CHANNELS;
251 for(i = 0; (uint32_t)i < ul1; i++) {
252 int16_t s1, s2, s3;
253 ul2 = getleu32(buf, OFFSET(2) + i * 3 * 4);
254 s1 = getles16(buf, OFFSET(3) + i * 3 * 4);
255 s2 = getles16(buf, OFFSET(3) + 2 + i * 3 * 4);
256 s3 = getles16(buf, OFFSET(4) + 2 + i * 3 * 4);
257 GPSD_LOG(LOG_INF, &session->context->errout,
258 "ID %d Az %g El %g SNR %g\n",
259 decode_channel_id(ul2), s1*0.001*RAD_2_DEG,
260 s2*0.001*RAD_2_DEG, s3*0.1);
261 session->gpsdata.skyview[i].PRN = (short)decode_channel_id(ul2);
262 session->gpsdata.skyview[i].azimuth = (short)round((double)s1*0.001 * RAD_2_DEG);
263 session->gpsdata.skyview[i].elevation = (short)round((double)s2*0.001 * RAD_2_DEG);
264 session->gpsdata.skyview[i].ss = (double)s3*0.1;
265 session->gpsdata.skyview[i].used = (bool)(ul2 & (1<<27));
266 }
267 session->gpsdata.skyview_time.tv_sec = 0;
268 session->gpsdata.skyview_time.tv_nsec = 0;
269 mask |= SATELLITE_SET | USED_IS;
270 break;
271 case 0x3e:
272 ul1 = getleu32(buf, OFFSET(1));
273 ul2 = getleu32(buf, OFFSET(2));
274 ul3 = getleu32(buf, OFFSET(3));
275 GPSD_LOG(LOG_INF, &session->context->errout,
276 "Receiver power-up message %d %d %d\n", ul1, ul2, ul3);
277 break;
278 case 0x3f:
279 ul1 = getleu32(buf, OFFSET(1));
280 ul2 = getleu32(buf, OFFSET(2));
281 GPSD_LOG(LOG_WARN, &session->context->errout,
282 "Negative acknowledge %x %d\n", ul1, ul2);
283 break;
284 case 0x40:
285 GPSD_LOG(LOG_INF, &session->context->errout,
286 "Response to Set initial parameters\n");
287 break;
288 case 0x41:
289 GPSD_LOG(LOG_INF, &session->context->errout,
290 "Response to Set serial ports parameters\n");
291 break;
292 case 0x42:
293 ul1 = getleu32(buf, OFFSET(1));
294 ul2 = getleu32(buf, OFFSET(2));
295 ul3 = getleu32(buf, OFFSET(3));
296 GPSD_LOG(LOG_INF, &session->context->errout,
297 "Response to Set receiver operation mode %d %d %d\n",
298 ul1, ul2, ul3);
299 break;
300 case 0x43:
301 GPSD_LOG(LOG_INF, &session->context->errout,
302 "Response to Set navigation task solution parameters\n");
303 break;
304 case 0x44:
305 GPSD_LOG(LOG_INF, &session->context->errout,
306 "Response to Set output data rate\n");
307 break;
308 case 0x46:
309 GPSD_LOG(LOG_INF, &session->context->errout,
310 "Response to Assign data protocol to communication port\n");
311 break;
312 case 0x48:
313 GPSD_LOG(LOG_INF, &session->context->errout,
314 "Response to Set GPS almanac\n");
315 break;
316 case 0x49:
317 GPSD_LOG(LOG_INF, &session->context->errout,
318 "Response to Set GLONASS almanac\n");
319 break;
320 case 0x4a:
321 GPSD_LOG(LOG_INF, &session->context->errout,
322 "Response to Set GPS ephemeris\n");
323 break;
324 case 0x4b:
325 GPSD_LOG(LOG_INF, &session->context->errout,
326 "Response to Set GLONASS ephemeris\n");
327 break;
328 case 0x4c:
329 ul1 = getleu32(buf, OFFSET(1));
330 ul2 = getleu32(buf, OFFSET(2));
331 ul3 = getleu32(buf, OFFSET(3));
332 ul4 = getleu32(buf, OFFSET(4));
333 ul5 = getleu32(buf, OFFSET(5));
334 GPSD_LOG(LOG_INF, &session->context->errout,
335 "Response to Set PPS parameters %d %d %d %d %d\n",
336 ul1, ul2, ul3, ul4, ul5);
337 break;
338 case 0x4d:
339 GPSD_LOG(LOG_INF, &session->context->errout,
340 "Response to Enable/disable SV in position fix\n");
341 break;
342 case 0x4e:
343 GPSD_LOG(LOG_INF, &session->context->errout,
344 "Response to Enable/disable NMEA messages\n");
345 break;
346 case 0x4f:
347 ul1 = getleu32(buf, OFFSET(1));
348 ul2 = getleu32(buf, OFFSET(2));
349 GPSD_LOG(LOG_INF, &session->context->errout,
350 "Response to Enable/disable binary messages %x %x\n",
351 ul1, ul2);
352 break;
353 case 0x80:
354 GPSD_LOG(LOG_INF, &session->context->errout,
355 "Response to Query initial parameters\n");
356 break;
357 case 0x81:
358 GPSD_LOG(LOG_INF, &session->context->errout,
359 "Response to Query serial ports parameters\n");
360 break;
361 case 0x82:
362 ul1 = getleu32(buf, OFFSET(1));
363 ul2 = getleu32(buf, OFFSET(2));
364 ul3 = getleu32(buf, OFFSET(3));
365 GPSD_LOG(LOG_INF, &session->context->errout,
366 "Response to Query receiver operation mode %d %d %d\n",
367 ul1, ul2, ul3);
368 break;
369 case 0x83:
370 GPSD_LOG(LOG_INF, &session->context->errout,
371 "Response to Query navigation task solution parameters\n");
372 break;
373 case 0x84:
374 GPSD_LOG(LOG_INF, &session->context->errout,
375 "Response to Query output data rate\n");
376 break;
377 case 0x86:
378 session->driver.geostar.physical_port = (unsigned int)getleu32(buf, OFFSET(1));
379 GPSD_LOG(LOG_INF, &session->context->errout,
380 "Response to Query data protocol assignment to communication port\n");
381 GPSD_LOG(LOG_INF, &session->context->errout,
382 "Connected to physical port %d\n",
383 session->driver.geostar.physical_port);
384 break;
385 case 0x88:
386 GPSD_LOG(LOG_INF, &session->context->errout,
387 "Response to Query GPS almanac\n");
388 break;
389 case 0x89:
390 GPSD_LOG(LOG_INF, &session->context->errout,
391 "Response to Query GLONASS almanac\n");
392 break;
393 case 0x8a:
394 GPSD_LOG(LOG_INF, &session->context->errout,
395 "Response to Query GPS ephemerides\n");
396 break;
397 case 0x8b:
398 d1 = getled64(buf, OFFSET(23));
399 d2 = getled64(buf, OFFSET(25));
400 d3 = getled64(buf, OFFSET(27));
401 GPSD_LOG(LOG_INF, &session->context->errout,
402 "Response to Query GLONASS ephemerides %g %g %g\n",
403 d1, d2, d3);
404 break;
405 case 0x8c:
406 ul1 = getleu32(buf, OFFSET(1));
407 ul2 = getleu32(buf, OFFSET(2));
408 ul3 = getleu32(buf, OFFSET(3));
409 ul4 = getleu32(buf, OFFSET(4));
410 ul5 = getleu32(buf, OFFSET(5));
411 GPSD_LOG(LOG_INF, &session->context->errout,
412 "Response to Query PPS parameters %d %d %d %d %d\n",
413 ul1, ul2, ul3, ul4, ul5);
414 break;
415 case 0x8d:
416 GPSD_LOG(LOG_INF, &session->context->errout,
417 "Response to Query enable/disable status of the SV in position fix\n");
418 break;
419 case 0x8e:
420 GPSD_LOG(LOG_INF, &session->context->errout,
421 "Response to Query enable NMEA messages\n");
422 break;
423 case 0x8f:
424 ul1 = getleu32(buf, OFFSET(1));
425 ul2 = getleu32(buf, OFFSET(2));
426 GPSD_LOG(LOG_INF, &session->context->errout,
427 "Response to Query enable binary messages %x %x\n",
428 ul1, ul2);
429 break;
430 case 0xc0:
431 GPSD_LOG(LOG_INF, &session->context->errout,
432 "Response to Change operation mode command\n");
433 break;
434 case 0xc1:
435 ul4 = getleu32(buf, OFFSET(1));
436 ul1 = getleu32(buf, OFFSET(2));
437 ul2 = getleu32(buf, OFFSET(3));
438 ul3 = getleu32(buf, OFFSET(4));
439 (void)snprintf(session->subtype, sizeof(session->subtype),
440 "%u.%u %u.%u.%u %x %c-%u\n",
441 ul4>>16, ul4&0xFFFF, ul1>>9, (ul1>>5)&0xF, ul1&0x1F, ul2,
442 ul3>>24, ul3&0x00FFFFFF);
443 GPSD_LOG(LOG_INF, &session->context->errout,
444 "Response to Request FW version command: %s\n",
445 session->subtype);
446 mask |= DEVICEID_SET;
447 break;
448 case 0xc2:
449 GPSD_LOG(LOG_INF, &session->context->errout,
450 "Response to Restart receiver command\n");
451 break;
452 case 0xc3:
453 GPSD_LOG(LOG_INF, &session->context->errout,
454 "Response to Store parameters to Flash command\n");
455 break;
456 case 0xd0:
457 GPSD_LOG(LOG_INF, &session->context->errout,
458 "Response to Erase Flash sector command\n");
459 break;
460 case 0xd1:
461 GPSD_LOG(LOG_INF, &session->context->errout,
462 "Response to Write data to Flash command\n");
463 break;
464 case 0xd2:
465 GPSD_LOG(LOG_INF, &session->context->errout,
466 "Response to Store Serial Number command\n");
467 break;
468 default:
469 GPSD_LOG(LOG_WARN, &session->context->errout,
470 "Unhandled GeoStar packet type 0x%02x\n", id);
471 break;
472 }
473
474 return mask;
475 }
476
geostar_parse_input(struct gps_device_t * session)477 static gps_mask_t geostar_parse_input(struct gps_device_t *session)
478 {
479 if (session->lexer.type == GEOSTAR_PACKET) {
480 return geostar_analyze(session);;
481 } else
482 return 0;
483 }
484
485 #ifdef CONTROLSEND_ENABLE
geostar_control_send(struct gps_device_t * session,char * buf,size_t buflen)486 static ssize_t geostar_control_send(struct gps_device_t *session,
487 char *buf, size_t buflen)
488 /* not used by the daemon, it's for gpsctl and friends */
489 {
490 return (ssize_t) geostar_write(session,
491 (unsigned int)buf[0],
492 (unsigned char *)buf + 1, (buflen - 1)/4);
493 }
494 #endif /* CONTROLSEND_ENABLE */
495
496
geostar_init_query(struct gps_device_t * session)497 static void geostar_init_query(struct gps_device_t *session)
498 {
499 unsigned char buf[2 * 4];
500 /* Poll Software Version */
501 (void)geostar_write(session, 0xc1, buf, 1);
502 }
503
geostar_event_hook(struct gps_device_t * session,event_t event)504 static void geostar_event_hook(struct gps_device_t *session, event_t event)
505 {
506 unsigned char buf[2 * 4];
507
508 if (session->context->readonly)
509 return;
510
511 if (event == event_identified || event == event_reactivate) {
512 /* Select binary packets */
513 putbe32(buf, 0, 0xffff0000);
514 putbe32(buf, 4, 0);
515 (void)geostar_write(session, 0x4f, buf, 2);
516
517 /* Poll Ports params */
518 putbe32(buf, 0, 1);
519 (void)geostar_write(session, 0x81, buf, 1);
520 putbe32(buf, 0, 0);
521 (void)geostar_write(session, 0x81, buf, 1);
522 /* Poll Init params */
523 (void)geostar_write(session, 0x80, buf, 1);
524 /* Poll Mode */
525 (void)geostar_write(session, 0x82, buf, 1);
526 /* Poll Solution params */
527 (void)geostar_write(session, 0x83, buf, 1);
528 /* Poll Output rate */
529 (void)geostar_write(session, 0x84, buf, 1);
530 /* Poll Protocols assignment */
531 (void)geostar_write(session, 0x86, buf, 1);
532 /* Poll PPS params */
533 (void)geostar_write(session, 0x8c, buf, 1);
534 /* Poll NMEA packets selected */
535 (void)geostar_write(session, 0x8e, buf, 1);
536 /* Poll binary packets selected */
537 (void)geostar_write(session, 0x8f, buf, 1);
538 }
539
540 if (event == event_deactivate) {
541 /* Perform cold restart */
542 putbe32(buf, 0, 3);
543 (void)geostar_write(session, 0xc2, buf, 1);
544 }
545 }
546
547 #ifdef RECONFIGURE_ENABLE
geostar_speed_switch(struct gps_device_t * session,speed_t speed,char parity,int stopbits)548 static bool geostar_speed_switch(struct gps_device_t *session,
549 speed_t speed, char parity, int stopbits)
550 {
551 unsigned char buf[4 * 4];
552 int iparity;
553
554 switch (parity) {
555 case 'E':
556 case 2:
557 parity = (char)2;
558 break;
559 case 'O':
560 case 1:
561 parity = (char)1;
562 break;
563 case 'N':
564 case 0:
565 default:
566 parity = (char)0;
567 break;
568 }
569 iparity = parity;
570
571 putbe32(buf, 0, session->driver.geostar.physical_port);
572 putbe32(buf, 4, speed);
573 putbe32(buf, 8, stopbits);
574 putbe32(buf, 12, iparity);
575 (void)geostar_write(session, 0x41, buf, 4);
576
577 return true; /* it would be nice to error-check this */
578 }
579
geostar_mode(struct gps_device_t * session,int mode)580 static void geostar_mode(struct gps_device_t *session, int mode)
581 {
582 if (mode == MODE_NMEA) {
583 unsigned char buf[1 * 4];
584 /* Switch to NMEA mode */
585 putbe32(buf, 0, 1);
586 (void)geostar_write(session, 0x46, buf, 1);
587 } else if (mode == MODE_BINARY) {
588 /* Switch to binary mode */
589 (void)nmea_send(session, "$GPSGG,SWPROT");
590 } else {
591 GPSD_LOG(LOG_ERROR, &session->context->errout,
592 "unknown mode %i requested\n", mode);
593 }
594 }
595 #endif /* RECONFIGURE_ENABLE */
596
geostar_time_offset(struct gps_device_t * session UNUSED)597 static double geostar_time_offset(struct gps_device_t *session UNUSED)
598 {
599 return 0.31;
600 }
601
602 /* this is everything we export */
603 /* *INDENT-OFF* */
604 const struct gps_type_t driver_geostar =
605 {
606 .type_name = "GeoStar", /* full name of type */
607 .packet_type = GEOSTAR_PACKET, /* associated lexer packet type */
608 .flags = DRIVER_STICKY, /* remember this */
609 .trigger = NULL, /* no trigger */
610 .channels = GEOSTAR_CHANNELS, /* consumer-grade GPS/GLONASS */
611 .probe_detect = geostar_detect, /* probe for device */
612 .get_packet = generic_get, /* use the generic packet getter */
613 .parse_packet = geostar_parse_input, /* parse message packets */
614 .rtcm_writer = NULL, /* doesn't accept DGPS corrections */
615 .init_query = geostar_init_query, /* non-perturbing initial query */
616 .event_hook = geostar_event_hook, /* fire on various lifetime events */
617 #ifdef RECONFIGURE_ENABLE
618 .speed_switcher = geostar_speed_switch,/* change baud rate */
619 .mode_switcher = geostar_mode, /* there is a mode switcher */
620 .rate_switcher = NULL, /* no rate switcher */
621 .min_cycle.tv_sec = 1, /* not relevant, no rate switch */
622 .min_cycle.tv_nsec = 0, /* not relevant, no rate switch */
623 #endif /* RECONFIGURE_ENABLE */
624 #ifdef CONTROLSEND_ENABLE
625 .control_send = geostar_control_send,/* how to send commands */
626 #endif /* CONTROLSEND_ENABLE */
627 .time_offset = geostar_time_offset,
628 };
629 /* *INDENT-ON* */
630
631 #endif /* GEOSTAR_ENABLE */
632