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