Coverage Report

Created: 2024-02-25 06:36

/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