Coverage Report

Created: 2026-06-04 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/gpsd/subframe.c
Line
Count
Source
1
/* subframe.c -- interpret satellite subframe data.
2
 *
3
 * This file is Copyright 2010 by the GPSD project
4
 * SPDX-License-Identifier: BSD-2-clause
5
 */
6
7
#include "../include/gpsd_config.h"  // must be before all includes
8
9
#include <math.h>
10
#include <string.h>                  // for memcpy()
11
12
#include "../include/gpsd.h"
13
#include "../include/bits.h"
14
15
// initialize an orbit_t
16
static void init_orbit(orbit_t *orbit)
17
3.06k
{
18
3.06k
    orbit->type = 0;
19
3.06k
    orbit->sv = 0;
20
3.06k
    orbit->AODC = -1;
21
3.06k
    orbit->AODE = -1;
22
3.06k
    orbit->IODA = -1;
23
3.06k
    orbit->IODC = -1;
24
3.06k
    orbit->IODE = -1;
25
3.06k
    orbit->E5bHS = -1;
26
3.06k
    orbit->E1BHS = -1;
27
3.06k
    orbit->SISAa = -1;
28
3.06k
    orbit->SISAb = -1;
29
3.06k
    orbit->toa = -1;
30
3.06k
    orbit->toc = -1;
31
3.06k
    orbit->toe = -1;
32
3.06k
    orbit->toeLSB = -1;
33
3.06k
    orbit->toeMSB = -1;
34
3.06k
    orbit->svh = -1;
35
3.06k
    orbit->URAI = -1;
36
3.06k
    orbit->WN = -1;
37
3.06k
    orbit->af0 = NAN;
38
3.06k
    orbit->af1 = NAN;
39
3.06k
    orbit->af2 = NAN;
40
3.06k
    orbit->alpha0 = NAN;
41
3.06k
    orbit->alpha1 = NAN;
42
3.06k
    orbit->alpha2 = NAN;
43
3.06k
    orbit->alpha3 = NAN;
44
3.06k
    orbit->beta0 = NAN;
45
3.06k
    orbit->beta1 = NAN;
46
3.06k
    orbit->beta2 = NAN;
47
3.06k
    orbit->beta3 = NAN;
48
3.06k
    orbit->Cic = NAN;
49
3.06k
    orbit->Cis = NAN;
50
3.06k
    orbit->Crc = NAN;
51
3.06k
    orbit->Crs = NAN;
52
3.06k
    orbit->Cuc = NAN;
53
3.06k
    orbit->Cus = NAN;
54
3.06k
    orbit->deltai = NAN;
55
3.06k
    orbit->deltan = NAN;
56
3.06k
    orbit->eccentricity = NAN;
57
3.06k
    orbit->i0 = NAN;
58
3.06k
    orbit->IDOT = NAN;
59
3.06k
    orbit->M0 = NAN;
60
3.06k
    orbit->Omega0 = NAN;
61
3.06k
    orbit->Omegad = NAN;
62
3.06k
    orbit->omega = NAN;
63
3.06k
    orbit->sqrtA = NAN;
64
3.06k
    orbit->TGD1 = NAN;
65
3.06k
    orbit->TGD2 = NAN;
66
3.06k
}
67
68
// init a subrame_t
69
static void init_subframe(struct subframe_t *subp, gnssid_t gnssId,
70
                          uint8_t tSVID)
71
3.06k
{
72
3.06k
    memset(subp, 0, sizeof(struct subframe_t));
73
3.06k
    subp->gnssId = gnssId;
74
3.06k
    subp->tSVID = tSVID;
75
3.06k
    subp->WN = -1;
76
3.06k
    subp->TOW17 = -1;
77
3.06k
    init_orbit(&subp->orbit);
78
3.06k
    memcpy(&subp->orbit1, &subp->orbit, sizeof(subp->orbit1));
79
3.06k
}
80
81
/* you can find up to date almanac data for comparison here:
82
 * https://gps.afspc.af.mil/gps/Current/current.alm
83
 *
84
 * Current ephermeis here, note URL split:
85
 *  https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/
86
 *        broadcast_ephemeris_data.html#GPShourly
87
 */
88
static void subframe_almanac(const struct gpsd_errout_t *errout,
89
                             uint8_t tSVID, uint32_t words[],
90
                             uint8_t subframe, uint8_t sv,
91
                             uint8_t data_id,
92
                             struct almanac_t *almp)
93
853
{
94
853
    almp->sv     = sv;  // ignore the 0 sv problem for now
95
853
    almp->e      = ( words[2] & BITMASK(16));
96
853
    almp->d_eccentricity  = pow(2.0, -21) * almp->e;
97
    /* careful, each SV can have more than 2 toa's active at the same time
98
     * you can not just store one or two almanacs for each sat */
99
853
    almp->toa      = ((words[3] >> 16) & BITMASK(8));
100
853
    almp->l_toa    = (long)almp->toa << 12;
101
    // Inclination Angle at Reference Time
102
    // Relative to i0 = 0.30 semi-circles
103
853
    almp->deltai   = (int16_t)( words[3] & BITMASK(16));
104
853
    almp->d_deltai = pow(2.0, -19) * almp->deltai;
105
    // Rate of Right Ascension, semi-circles/sec
106
853
    almp->Omegad   = (int16_t)((words[4] >>  8) & BITMASK(16));
107
    // -1.19E-07 to 0, semi-circles/sec
108
853
    almp->d_Omegad = pow(2.0, -38) * almp->Omegad;
109
853
    almp->svh      = ( words[4] & BITMASK(8));
110
853
    almp->sqrtA    = ( words[5] & BITMASK(24));
111
853
    almp->d_sqrtA  = pow(2.0, -11) * almp->sqrtA;
112
    // Longitude of Ascending Node of Orbit Plane at Weekly Epoch, semi-circles
113
    // aka Tight Ascen at Week
114
853
    almp->Omega0   = ( words[6] & BITMASK(24));
115
853
    almp->Omega0   = UINT2INT(almp->Omega0, 24);
116
853
    almp->d_Omega0 = pow(2.0, -23) * almp->Omega0;
117
    // Argument of Perigee, semi-circles
118
853
    almp->omega    = ( words[7] & BITMASK(24));
119
853
    almp->omega    = UINT2INT(almp->omega, 24);
120
853
    almp->d_omega  = pow(2.0, -23) * almp->omega;
121
    // Mean Anomaly at Reference Time, semi-circles
122
853
    almp->M0 = words[8] & BITMASK(24);
123
853
    almp->M0 = UINT2INT(almp->M0, 24);
124
    /* if you want radians, multiply by GPS_PI, but we do semi-circles
125
     * to match IS-GPS-200 */
126
853
    almp->d_M0     = pow(2.0, -23) * almp->M0;
127
    // SV Clock Drift Correction Coefficient, seconds/second
128
853
    almp->af1      = ((words[9] >>  5) & BITMASK(11));
129
853
    almp->af1      = (short)UINT2INT(almp->af1, 11);
130
853
    almp->d_af1    = pow(2.0, -38) * almp->af1;
131
    // SV Clock Bias Correction Coefficient, seconds
132
853
    almp->af0      = ((words[9] >> 16) & BITMASK(8));
133
853
    almp->af0    <<= 3;
134
853
    almp->af0     |= ((words[9] >>  2) & BITMASK(3));
135
853
    almp->af0      = (short)UINT2INT(almp->af0, 11);
136
853
    almp->d_af0    = pow(2.0, -20) * almp->af0;
137
853
    GPSD_LOG(LOG_PROG, errout,
138
853
             "SUB,GPS: SF:%d SV:%2u TSV:%2u data_id %d e:%g toa:%lu "
139
853
             "deltai:%.10e Omegad:%.5e svh:%u sqrtA:%.10g Omega0:%.10e "
140
853
             "omega:%.10e M0:%.11e af0:%.5e af1:%.5e\n",
141
853
             subframe, almp->sv, tSVID, data_id,
142
853
             almp->d_eccentricity,
143
853
             almp->l_toa,
144
853
             almp->d_deltai,
145
853
             almp->d_Omegad,
146
853
             almp->svh,
147
853
             almp->d_sqrtA,
148
853
             almp->d_Omega0,
149
853
             almp->d_omega,
150
853
             almp->d_M0,
151
853
             almp->d_af0,
152
853
             almp->d_af1);
153
853
}
154
155
// interpret GPS subframes
156
gps_mask_t gpsd_interpret_subframe(struct gps_device_t *session,
157
                                   gnssid_t gnssId, unsigned int tSVID,
158
                                   uint32_t words[])
159
3.06k
{
160
    /*
161
     * Heavy black magic begins here!
162
     *
163
     * A description of how to decode these bits is at
164
     * <http://home-2.worldonline.nl/~samsvl/nav2eu.htm>
165
     *
166
     * This functions assumes an array of words without parity or inversion.
167
     * Inverted word 0 is OK.
168
     * May be called directly by a driver if the chipset emits acceptable data.
169
     *
170
     * To date this code has been tested on iTrax, SiRF and ublox.
171
     */
172
    // FIXME!! I really doubt this is Big Endian compatible
173
3.06k
    uint8_t preamble;
174
3.06k
    struct subframe_t *subp = &session->gpsdata.subframe;
175
3.06k
    init_subframe(&session->gpsdata.subframe, gnssId, (uint8_t)tSVID);
176
177
3.06k
    GPSD_LOG(LOG_DATA, &session->context->errout,
178
3.06k
             "SUB,GPS: gpsd_interpret_subframe: (%u, %u) "
179
3.06k
             "%06x %06x %06x %06x %06x %06x %06x %06x %06x %06x\n",
180
3.06k
             gnssId, tSVID, words[0], words[1], words[2], words[3], words[4],
181
3.06k
             words[5], words[6], words[7], words[8], words[9]);
182
183
3.06k
    if (GNSSID_GPS != gnssId) {
184
0
        GPSD_LOG(LOG_INFO, &session->context->errout,
185
0
                 "SUB,GPS: Unsupportd gnssId %u\n", gnssId);
186
0
        return 0;
187
0
    }
188
3.06k
    preamble = (uint8_t)((words[0] >> 16) & BITMASK(8));
189
3.06k
    if (preamble == 0x8b) {
190
        // somehow missed an inversion
191
2.57k
        preamble ^= BITMASK(8);
192
2.57k
        words[0] ^= BITMASK(24);
193
2.57k
    }
194
3.06k
    if (preamble != 0x74) {
195
98
        GPSD_LOG(LOG_WARN, &session->context->errout,
196
98
                 "SUB,GPS: gpsd_interpret_subframe bad preamble: "
197
98
                 "0x%x header 0x%x\n",
198
98
                 preamble, words[0]);
199
98
        return 0;
200
98
    }
201
2.97k
    subp->integrity = (bool)((words[0] >> 1) & 1);
202
    // The subframe ID is in the Hand Over Word (page 80)
203
    // subframe_num is 1 to 5
204
2.97k
    subp->subframe_num = ((words[1] >> 2) & BITMASK(3));
205
2.97k
    subp->antispoof = (bool)((words[1] >> 5) & 1);
206
2.97k
    subp->alert = (bool)((words[1] >> 6) & 1);
207
2.97k
    subp->TOW17 = (long)((words[1] >> 7) & BITMASK(17)) * 6;
208
2.97k
    GPSD_LOG(LOG_PROG, &session->context->errout,
209
2.97k
             "SUB,GPS: SF:%d SV:%2u TOW17:%7d Alert:%u AS:%u IF:%d\n",
210
2.97k
             subp->subframe_num, subp->tSVID, subp->TOW17,
211
2.97k
             (unsigned)subp->alert, (unsigned)subp->antispoof,
212
2.97k
             (unsigned)subp->integrity);
213
    /*
214
     * Consult the latest revision of IS-GPS-200 for the mapping
215
     * between magic SVIDs and pages.
216
     */
217
2.97k
    subp->pageid  = (words[2] >> 16) & BITMASK(6);  // only in frames 4 & 5
218
2.97k
    subp->data_id = (words[2] >> 22) & 3;           // only in frames 4 & 5
219
2.97k
    subp->is_almanac = 0;
220
221
2.97k
    switch (subp->subframe_num) {
222
152
    case 1:
223
        // subframe 1: clock parameters for transmitting SV
224
        // get Week Number (WN) from subframe 1
225
        /*
226
         * This only extracts 10 bits of GPS week.
227
         * 13 bits are available in the extension CNAV message,
228
         * which we don't decode yet because we don't know
229
         * of any receiver that reports it.
230
         */
231
152
        session->context->gps_week =
232
152
            (unsigned short)((words[2] >> 14) & BITMASK(10));
233
152
        subp->sub1.WN   = (uint16_t)session->context->gps_week;
234
152
        subp->sub1.l2   = (uint8_t)((words[2] >> 12) & 3);   // L2 Code
235
        // URA Index
236
152
        subp->sub1.ura  = (unsigned int)((words[2] >>  8) & BITMASK(4));
237
        // SV health
238
152
        subp->sub1.hlth = (unsigned int)((words[2] >>  2) & BITMASK(6));
239
152
        subp->sub1.IODC = (words[2] & 3);                  // IODC 2 MSB
240
152
        subp->sub1.l2p  = ((words[3] >> 23) & 1);          // L2 P flag
241
152
        subp->sub1.Tgd  = (int8_t)( words[6] & BITMASK(8));
242
152
        subp->sub1.d_Tgd  = pow(2.0, -31) * (int)subp->sub1.Tgd;
243
152
        subp->sub1.toc  = ( words[7] & BITMASK(16));
244
152
        subp->sub1.l_toc = (long)subp->sub1.toc  << 4;
245
152
        subp->sub1.af2  = (int8_t)((words[8] >> 16) & BITMASK(8));
246
152
        subp->sub1.d_af2  = pow(2.0, -55) * (int)subp->sub1.af2;
247
152
        subp->sub1.af1  = (int16_t)( words[8] & BITMASK(16));
248
152
        subp->sub1.d_af1  = pow(2.0, -43) * subp->sub1.af1;
249
152
        subp->sub1.af0  = (int32_t)((words[9] >>  2) & BITMASK(22));
250
152
        subp->sub1.af0  = UINT2INT(subp->sub1.af0, 22);
251
152
        subp->sub1.d_af0  = pow(2.0, -31) * subp->sub1.af0;
252
152
        subp->sub1.IODC <<= 8;
253
152
        subp->sub1.IODC |= ((words[7] >> 16) & BITMASK(8));
254
152
        GPSD_LOG(LOG_PROG, &session->context->errout,
255
152
                 "SUB,GPS: SF:1 SV:%2u WN:%4u IODC:%4u"
256
152
                 " L2:%u ura:%u hlth:%u L2P:%u Tgd:%g toc:%lu af2:%.4g"
257
152
                 " af1:%.6e af0:%.7e\n",
258
152
                 subp->tSVID,
259
152
                 subp->sub1.WN,
260
152
                 subp->sub1.IODC,
261
152
                 subp->sub1.l2,
262
152
                 subp->sub1.ura,
263
152
                 subp->sub1.hlth,
264
152
                 subp->sub1.l2p,
265
152
                 subp->sub1.d_Tgd,
266
152
                 subp->sub1.l_toc,
267
152
                 subp->sub1.d_af2,
268
152
                 subp->sub1.d_af1,
269
152
                 subp->sub1.d_af0);
270
152
        break;
271
87
    case 2:
272
        // subframe 2: ephemeris for transmitting SV
273
87
        subp->sub2.IODE   = ((words[2] >> 16) & BITMASK(8));
274
87
        subp->sub2.Crs    = (int16_t)( words[2] & BITMASK(16));
275
87
        subp->sub2.d_Crs  = pow(2.0, -5) * subp->sub2.Crs;
276
87
        subp->sub2.deltan = (int16_t)((words[3] >>  8) & BITMASK(16));
277
87
        subp->sub2.d_deltan  = pow(2.0, -43) * subp->sub2.deltan;
278
87
        subp->sub2.M0     = (int32_t)( words[3] & BITMASK(8));
279
87
        subp->sub2.M0   <<= 24;
280
87
        subp->sub2.M0    |= ( words[4] & BITMASK(24));
281
        /* if you want radians, multiply by GPS_PI, but we do semi-circles
282
         * to match IS-GPS-200 */
283
87
        subp->sub2.d_M0   = pow(2.0, -31) * subp->sub2.M0;
284
87
        subp->sub2.Cuc    = (int16_t)((words[5] >>  8) & BITMASK(16));
285
87
        subp->sub2.d_Cuc  = pow(2.0, -29) * subp->sub2.Cuc;
286
87
        subp->sub2.e      = ( words[5] & BITMASK(8));
287
87
        subp->sub2.e    <<= 24;
288
87
        subp->sub2.e     |= ( words[6] & BITMASK(24));
289
87
        subp->sub2.d_eccentricity  = pow(2.0, -33) * subp->sub2.e;
290
87
        subp->sub2.Cus    = (int16_t)((words[7] >>  8) & BITMASK(16));
291
87
        subp->sub2.d_Cus  = pow(2.0, -29) * subp->sub2.Cus;
292
87
        subp->sub2.sqrtA  = ( words[7] & BITMASK(8));
293
87
        subp->sub2.sqrtA <<= 24;
294
87
        subp->sub2.sqrtA |= ( words[8] & BITMASK(24));
295
87
        subp->sub2.d_sqrtA = pow(2.0, -19) * subp->sub2.sqrtA;
296
87
        subp->sub2.toe    = ((words[9] >>  8) & BITMASK(16));
297
87
        subp->sub2.l_toe  = ((unsigned long)subp->sub2.toe << 4);
298
87
        subp->sub2.fit    = ((words[9] >>  7) & 1);
299
87
        subp->sub2.AODO   = ((words[9] >>  2) & BITMASK(5));
300
87
        subp->sub2.u_AODO   = subp->sub2.AODO * 900;
301
87
        GPSD_LOG(LOG_PROG, &session->context->errout,
302
87
                 "SUB,GPS: SF:2 SV:%2u IODE:%3u Crs:%.6e deltan:%.6e "
303
87
                 "M0:%.11e Cuc:%.6e e:%f Cus:%.6e sqrtA:%.11g "
304
87
                 "toe:%lu FIT:%u AODO:%5u\n",
305
87
                 subp->tSVID,
306
87
                 subp->sub2.IODE,
307
87
                 subp->sub2.d_Crs,
308
87
                 subp->sub2.d_deltan,
309
87
                 subp->sub2.d_M0,
310
87
                 subp->sub2.d_Cuc,
311
87
                 subp->sub2.d_eccentricity,
312
87
                 subp->sub2.d_Cus,
313
87
                 subp->sub2.d_sqrtA,
314
87
                 subp->sub2.l_toe,
315
87
                 subp->sub2.fit,
316
87
                 subp->sub2.u_AODO);
317
87
        break;
318
179
    case 3:
319
        // subframe 3: ephemeris for transmitting SV
320
179
        subp->sub3.Cic      = (int16_t)((words[2] >>  8) & BITMASK(16));
321
179
        subp->sub3.d_Cic    = pow(2.0, -29) * subp->sub3.Cic;
322
179
        subp->sub3.Omega0   = (int32_t)(words[2] & BITMASK(8));
323
179
        subp->sub3.Omega0 <<= 24;
324
179
        subp->sub3.Omega0  |= ( words[3] & BITMASK(24));
325
179
        subp->sub3.d_Omega0 = pow(2.0, -31) * subp->sub3.Omega0;
326
179
        subp->sub3.Cis      = (int16_t)((words[4] >>  8) & BITMASK(16));
327
179
        subp->sub3.d_Cis    = pow(2.0, -29) * subp->sub3.Cis;
328
179
        subp->sub3.i0       = (int32_t)(words[4] & BITMASK(8));
329
179
        subp->sub3.i0     <<= 24;
330
179
        subp->sub3.i0      |= ( words[5] & BITMASK(24));
331
179
        subp->sub3.d_i0     = pow(2.0, -31) * subp->sub3.i0;
332
179
        subp->sub3.Crc      = (int16_t)((words[6] >>  8) & BITMASK(16));
333
179
        subp->sub3.d_Crc    = pow(2.0, -5) * subp->sub3.Crc;
334
179
        subp->sub3.omega    = (int32_t)(words[6] & BITMASK(8));
335
179
        subp->sub3.omega  <<= 24;
336
179
        subp->sub3.omega   |= ( words[7] & BITMASK(24));
337
179
        subp->sub3.d_omega  = pow(2.0, -31) * subp->sub3.omega;
338
        // Rate of Right Ascension
339
179
        subp->sub3.Omegad   = (int32_t)(words[8] & BITMASK(24));
340
179
        subp->sub3.Omegad   = UINT2INT(subp->sub3.Omegad, 24);
341
        // -6.33E-07 to 0, semi-circles/sec
342
179
        subp->sub3.d_Omegad = pow(2.0, -43) * subp->sub3.Omegad;
343
179
        subp->sub3.IODE     = ((words[9] >> 16) & BITMASK(8));
344
179
        subp->sub3.IDOT     = (int16_t)((words[9] >>  2) & BITMASK(14));
345
179
        subp->sub3.IDOT     = UINT2INT(subp->sub3.IDOT, 14);
346
179
        subp->sub3.d_IDOT   = pow(2.0, -43) * subp->sub3.IDOT;
347
179
        GPSD_LOG(LOG_PROG, &session->context->errout,
348
179
                 "SUB,GPS: SF:3 SV:%2u IODE:%3u I IDOT:%.6g Cic:%.6e "
349
179
                 "Omega0:%.11e Cis:%.7g i0:%.11e Crc:%.7g omega:%.11e "
350
179
                 "Omegad:%.6e\n",
351
179
                 subp->tSVID, subp->sub3.IODE, subp->sub3.d_IDOT,
352
179
                 subp->sub3.d_Cic, subp->sub3.d_Omega0, subp->sub3.d_Cis,
353
179
                 subp->sub3.d_i0, subp->sub3.d_Crc, subp->sub3.d_omega,
354
179
                 subp->sub3.d_Omegad );
355
179
        break;
356
2.23k
    case 4:
357
2.23k
        {
358
2.23k
            int i = 0;   // handy loop counter
359
2.23k
            int sv = -2;
360
2.23k
            switch (subp->pageid) {
361
120
            case 0:
362
                // almanac for dummy sat 0, which is same as transmitting sat
363
120
                sv = 0;
364
120
                break;
365
366
            // almanac data for SV 25 through 32 respectively;
367
70
            case 25:         // aka page 2:
368
70
                sv = 25;
369
70
                break;
370
85
            case 26:         // aka page 3:
371
85
                sv = 26;
372
85
                break;
373
67
            case 27:         // aka page 4:
374
67
                sv = 27;
375
67
                break;
376
90
            case 28:         // aka page 5:
377
90
                sv = 28;
378
90
                break;
379
87
            case 29:         // aka page 7
380
87
                sv = 29;
381
87
                break;
382
74
            case 30:         // aka page 8
383
74
                sv = 30;
384
74
                break;
385
97
            case 31:         // aka page 9
386
97
                sv = 31;
387
97
                break;
388
69
            case 32:         // aka page 10
389
69
                sv = 32;
390
69
                break;
391
392
699
            case 52:                  // aka page 13
393
                // NMCT
394
                // ERD can not be char as char may be signed or unsigned.
395
                // FIXME: shuffle SV into correct slot.
396
699
                sv = -1;
397
699
                subp->sub4_13.ai = (unsigned char)((words[2] >> 22) & 3);
398
699
                subp->sub4_13.ERD[1]  = (int8_t)((words[2] >>  8) & BITMASK(6));
399
699
                subp->sub4_13.ERD[2]  = (int8_t)((words[2] >>  2) & BITMASK(6));
400
699
                subp->sub4_13.ERD[3]  = (int8_t)((words[2] >>  0) & 3);
401
699
                subp->sub4_13.ERD[3] <<= 2;
402
699
                subp->sub4_13.ERD[3] |= (int8_t)((words[3] >> 20) & BITMASK(4));
403
404
699
                subp->sub4_13.ERD[4]  = (int8_t)((words[3] >> 14) & BITMASK(6));
405
699
                subp->sub4_13.ERD[5]  = (int8_t)((words[3] >>  8) & BITMASK(6));
406
699
                subp->sub4_13.ERD[6]  = (int8_t)((words[3] >>  2) & BITMASK(6));
407
699
                subp->sub4_13.ERD[7]  = (int8_t)((words[3] >>  0) & 3);
408
409
699
                subp->sub4_13.ERD[7] <<= 2;
410
699
                subp->sub4_13.ERD[7] |= (int8_t)((words[4] >> 20) &
411
699
                                                  BITMASK(4));
412
699
                subp->sub4_13.ERD[8]  = (int8_t)((words[4] >> 14) & BITMASK(6));
413
699
                subp->sub4_13.ERD[9]  = (int8_t)((words[4] >>  8) & BITMASK(6));
414
699
                subp->sub4_13.ERD[10] = (int8_t)((words[4] >>  2) & BITMASK(6));
415
699
                subp->sub4_13.ERD[11] = (int8_t)((words[4] >>  0) &
416
699
                                                  BITMASK(4));
417
418
699
                subp->sub4_13.ERD[11] <<= 2;
419
699
                subp->sub4_13.ERD[11] |= (int8_t)((words[5] >> 20) &
420
699
                                                  BITMASK(4));
421
699
                subp->sub4_13.ERD[12]  = (int8_t)((words[5] >> 14) & BITMASK(6));
422
699
                subp->sub4_13.ERD[13]  = (int8_t)((words[5] >>  8) & BITMASK(6));
423
699
                subp->sub4_13.ERD[14]  = (int8_t)((words[5] >>  2) & BITMASK(6));
424
699
                subp->sub4_13.ERD[15]  = (int8_t)((words[5] >>  0) & 3);
425
426
699
                subp->sub4_13.ERD[15] <<= 2;
427
699
                subp->sub4_13.ERD[15] |= (int8_t)((words[6] >> 20) &
428
699
                                                  BITMASK(4));
429
699
                subp->sub4_13.ERD[16]  = (int8_t)((words[6] >> 14) & BITMASK(6));
430
699
                subp->sub4_13.ERD[17]  = (int8_t)((words[6] >>  8) & BITMASK(6));
431
699
                subp->sub4_13.ERD[18]  = (int8_t)((words[6] >>  2) & BITMASK(6));
432
699
                subp->sub4_13.ERD[19]  = (int8_t)((words[6] >>  0) & 3);
433
434
699
                subp->sub4_13.ERD[19] <<= 2;
435
699
                subp->sub4_13.ERD[19] |= (int8_t)((words[7] >> 20) &
436
699
                                                  BITMASK(4));
437
699
                subp->sub4_13.ERD[20]  = (int8_t)((words[7] >> 14) & BITMASK(6));
438
699
                subp->sub4_13.ERD[21]  = (int8_t)((words[7] >>  8) & BITMASK(6));
439
699
                subp->sub4_13.ERD[22]  = (int8_t)((words[7] >>  2) & BITMASK(6));
440
699
                subp->sub4_13.ERD[23]  = (int8_t)((words[7] >>  0) & 3);
441
442
699
                subp->sub4_13.ERD[23] <<= 2;
443
699
                subp->sub4_13.ERD[23] |= (int8_t)((words[8] >> 20) &
444
699
                                                  BITMASK(4));
445
699
                subp->sub4_13.ERD[24]  = (int8_t)((words[8] >> 14) & BITMASK(6));
446
699
                subp->sub4_13.ERD[25]  = (int8_t)((words[8] >>  8) & BITMASK(6));
447
699
                subp->sub4_13.ERD[26]  = (int8_t)((words[8] >>  2) & BITMASK(6));
448
699
                subp->sub4_13.ERD[27]  = (int8_t)((words[8] >>  0) & 3);
449
450
699
                subp->sub4_13.ERD[27] <<= 2;
451
699
                subp->sub4_13.ERD[27] |= (int8_t)((words[9] >> 20) &
452
699
                                                  BITMASK(4));
453
699
                subp->sub4_13.ERD[28]  = (int8_t)((words[9] >> 14) & BITMASK(6));
454
699
                subp->sub4_13.ERD[29]  = (int8_t)((words[9] >>  8) & BITMASK(6));
455
699
                subp->sub4_13.ERD[30]  = (int8_t)((words[9] >>  2) & BITMASK(6));
456
457
21.6k
                for (i = 1; i < 31; i++) {
458
                    // sign extend 6 bit to 8 bit
459
20.9k
                    subp->sub4_13.ERD[i]  = UINT2INT(subp->sub4_13.ERD[i], 6);
460
20.9k
                }
461
                // ERD for SV 32 never sent, test for it to shut up coverity.
462
699
                if (32 > subp->tSVID) {
463
                    // own ERD never transmitted
464
8.51k
                    for (i = 30; i >= subp->tSVID; i--) {
465
                        // do the shuffle up thing
466
7.97k
                        subp->sub4_13.ERD[i + 1]  = subp->sub4_13.ERD[i];
467
7.97k
                    }
468
                    // 0x20 sign extends to 0xe0, 0xe0 is -32
469
546
                    subp->sub4_13.ERD[subp->tSVID] = -32;
470
546
                }
471
472
699
                GPSD_LOG(LOG_PROG, &session->context->errout,
473
699
                         "SUB,GPS: SF:4-13 data_id %d ai:%u "
474
699
                         "ERD1:%d ERD2:%d ERD3:%d ERD4:%d "
475
699
                         "ERD5:%d ERD6:%d ERD7:%d ERD8:%d "
476
699
                         "ERD9:%d ERD10:%d ERD11:%d ERD12:%d "
477
699
                         "ERD13:%d ERD14:%d ERD15:%d ERD16:%d "
478
699
                         "ERD17:%d ERD18:%d ERD19:%d ERD20:%d "
479
699
                         "ERD21:%d ERD22:%d ERD23:%d ERD24:%d "
480
699
                         "ERD25:%d ERD26:%d ERD27:%d ERD28:%d "
481
699
                         "ERD29:%d ERD30:%d ERD31:%d\n",
482
699
                         subp->data_id, subp->sub4_13.ai,
483
699
                         subp->sub4_13.ERD[1], subp->sub4_13.ERD[2],
484
699
                         subp->sub4_13.ERD[3], subp->sub4_13.ERD[4],
485
699
                         subp->sub4_13.ERD[5], subp->sub4_13.ERD[6],
486
699
                         subp->sub4_13.ERD[7], subp->sub4_13.ERD[8],
487
699
                         subp->sub4_13.ERD[9], subp->sub4_13.ERD[10],
488
699
                         subp->sub4_13.ERD[11], subp->sub4_13.ERD[12],
489
699
                         subp->sub4_13.ERD[13], subp->sub4_13.ERD[14],
490
699
                         subp->sub4_13.ERD[15], subp->sub4_13.ERD[16],
491
699
                         subp->sub4_13.ERD[17], subp->sub4_13.ERD[18],
492
699
                         subp->sub4_13.ERD[19], subp->sub4_13.ERD[20],
493
699
                         subp->sub4_13.ERD[21], subp->sub4_13.ERD[22],
494
699
                         subp->sub4_13.ERD[23], subp->sub4_13.ERD[24],
495
699
                         subp->sub4_13.ERD[25], subp->sub4_13.ERD[26],
496
699
                         subp->sub4_13.ERD[27], subp->sub4_13.ERD[28],
497
699
                         subp->sub4_13.ERD[29], subp->sub4_13.ERD[30],
498
699
                         subp->sub4_13.ERD[31]);
499
699
                break;
500
501
0
            case 53:     // aka page 14
502
                /* for some inscrutable reason page 14 is sent
503
                 * as page 53, IS-GPS-200 Table 20-
504
                 * reserved */
505
0
                break;
506
507
0
            case 54:      // aka page 15
508
                /* for some inscrutable reason page 15 is sent
509
                 * as page 54, IS-GPS-200 Table 20-V
510
                 * reserved */
511
0
                break;
512
513
68
            case 55:  // aka page 17
514
                /* for some inscrutable reason page 17 is sent
515
                 * as page 55, IS-GPS-200 Table 20-V */
516
68
                sv = -1;
517
                /*
518
                 * "The requisite 176 bits shall occupy bits 9 through 24
519
                 * of word TWO, the 24 MSBs of words THREE through EIGHT,
520
                 * plus the 16 MSBs of word NINE." (word numbers changed
521
                 * to account for zero-indexing)
522
                 * Since we've already stripped the low six parity bits,
523
                 * and shifted the data to a byte boundary, we can just
524
                 * copy it out. */
525
526
68
                i = 0;
527
68
                subp->sub4_17.str[i++] = (words[2] >> 8) & BITMASK(8);
528
68
                subp->sub4_17.str[i++] = (words[2]) & BITMASK(8);
529
530
68
                subp->sub4_17.str[i++] = (words[3] >> 16) & BITMASK(8);
531
68
                subp->sub4_17.str[i++] = (words[3] >> 8) & BITMASK(8);
532
68
                subp->sub4_17.str[i++] = (words[3]) & BITMASK(8);
533
534
68
                subp->sub4_17.str[i++] = (words[4] >> 16) & BITMASK(8);
535
68
                subp->sub4_17.str[i++] = (words[4] >> 8) & BITMASK(8);
536
68
                subp->sub4_17.str[i++] = (words[4]) & BITMASK(8);
537
538
68
                subp->sub4_17.str[i++] = (words[5] >> 16) & BITMASK(8);
539
68
                subp->sub4_17.str[i++] = (words[5] >> 8) & BITMASK(8);
540
68
                subp->sub4_17.str[i++] = (words[5]) & BITMASK(8);
541
542
68
                subp->sub4_17.str[i++] = (words[6] >> 16) & BITMASK(8);
543
68
                subp->sub4_17.str[i++] = (words[6] >> 8) & BITMASK(8);
544
68
                subp->sub4_17.str[i++] = (words[6]) & BITMASK(8);
545
546
68
                subp->sub4_17.str[i++] = (words[7] >> 16) & BITMASK(8);
547
68
                subp->sub4_17.str[i++] = (words[7] >> 8) & BITMASK(8);
548
68
                subp->sub4_17.str[i++] = (words[7]) & BITMASK(8);
549
550
68
                subp->sub4_17.str[i++] = (words[8] >> 16) & BITMASK(8);
551
68
                subp->sub4_17.str[i++] = (words[8] >> 8) & BITMASK(8);
552
68
                subp->sub4_17.str[i++] = (words[8]) & BITMASK(8);
553
554
68
                subp->sub4_17.str[i++] = (words[9] >> 16) & BITMASK(8);
555
68
                subp->sub4_17.str[i++] = (words[9] >> 8) & BITMASK(8);
556
68
                subp->sub4_17.str[i] = '\0';
557
68
                GPSD_LOG(LOG_PROG, &session->context->errout,
558
68
                         "SUB,GPS: SF:4-17 system message: %.24s\n",
559
68
                         subp->sub4_17.str);
560
68
                break;
561
562
523
            case 56:         // aka page 18
563
                /* for some inscrutable reason page 18 is sent
564
                 * as page 56, IS-GPS-200 Table 20-V */
565
                // ionospheric and UTC data
566
567
523
                sv = -1;
568
                // current leap seconds
569
523
                subp->sub4_18.alpha0 = (int8_t)((words[2] >> 8) & BITMASK(8));
570
523
                subp->sub4_18.d_alpha0 = pow(2.0, -30) *
571
523
                                             (int)subp->sub4_18.alpha0;
572
523
                subp->sub4_18.alpha1 = (int8_t)((words[2] >> 0) & BITMASK(8));
573
523
                subp->sub4_18.d_alpha1 = pow(2.0, -27) *
574
523
                                            (int)subp->sub4_18.alpha1;
575
523
                subp->sub4_18.alpha2 = (int8_t)((words[3] >> 16) & BITMASK(8));
576
523
                subp->sub4_18.d_alpha2 = pow(2.0, -24) *
577
523
                                            (int)subp->sub4_18.alpha2;
578
523
                subp->sub4_18.alpha3 = (int8_t)((words[3] >>  8) & BITMASK(8));
579
523
                subp->sub4_18.d_alpha3 = pow(2.0, -24) *
580
523
                                            (int)subp->sub4_18.alpha3;
581
582
523
                subp->sub4_18.beta0  = (int8_t)((words[3] >>  0) & BITMASK(8));
583
523
                subp->sub4_18.d_beta0 = pow(2.0, 11) * (int)subp->sub4_18.beta0;
584
523
                subp->sub4_18.beta1  = (int8_t)((words[4] >> 16) & BITMASK(8));
585
523
                subp->sub4_18.d_beta1 = pow(2.0, 14) * (int)subp->sub4_18.beta1;
586
523
                subp->sub4_18.beta2  = (int8_t)((words[4] >>  8) & BITMASK(8));
587
523
                subp->sub4_18.d_beta2 = pow(2.0, 16) * (int)subp->sub4_18.beta2;
588
523
                subp->sub4_18.beta3  = (int8_t)((words[4] >>  0) & BITMASK(8));
589
523
                subp->sub4_18.d_beta3 = pow(2.0, 16) * (int)subp->sub4_18.beta3;
590
591
523
                subp->sub4_18.A1     = (int32_t)((words[5] >>  0) &
592
523
                                                 BITMASK(24));
593
523
                subp->sub4_18.A1     = UINT2INT(subp->sub4_18.A1, 24);
594
523
                subp->sub4_18.d_A1   = pow(2.0, -50) * subp->sub4_18.A1;
595
523
                subp->sub4_18.A0     = (int32_t)((words[6] >>  0) &
596
523
                                                 BITMASK(24));
597
523
                subp->sub4_18.A0   <<= 8;
598
523
                subp->sub4_18.A0    |= ((words[7] >> 16) & BITMASK(8));
599
523
                subp->sub4_18.d_A0   = pow(2.0, -30) * subp->sub4_18.A0;
600
601
                // careful WN is 10 bits, but WNt is 8 bits!
602
                // WNt (Week Number of LSF)
603
523
                subp->sub4_18.tot    = ((words[7] >> 8) & BITMASK(8));
604
523
                subp->sub4_18.t_tot  = (unsigned long)subp->sub4_18.tot << 12;
605
523
                subp->sub4_18.WNt    = ((words[7] >> 0) & BITMASK(8));
606
523
                subp->sub4_18.leap  = (int8_t)((words[8] >> 16) & BITMASK(8));
607
523
                subp->sub4_18.WNlsf  = ((words[8] >>  8) & BITMASK(8));
608
609
                // DN (Day Number of LSF)
610
523
                subp->sub4_18.DN = (words[8] & BITMASK(8));
611
                // leap second future
612
523
                subp->sub4_18.lsf = (int8_t)((words[9] >> 16) & BITMASK(8));
613
614
523
                GPSD_LOG(LOG_PROG, &session->context->errout,
615
523
                         "SUB,GPS: SF:4-18 a0:%.5g a1:%.5g a2:%.5g a3:%.5g "
616
523
                         "b0:%.5g b1:%.5g b2:%.5g b3:%.5g "
617
523
                         "A1:%.11e A0:%.11e tot:%lld WNt:%u "
618
523
                         "ls: %d WNlsf:%u DN:%u, lsf:%d\n",
619
523
                         subp->sub4_18.d_alpha0, subp->sub4_18.d_alpha1,
620
523
                         subp->sub4_18.d_alpha2, subp->sub4_18.d_alpha3,
621
523
                         subp->sub4_18.d_beta0, subp->sub4_18.d_beta1,
622
523
                         subp->sub4_18.d_beta2, subp->sub4_18.d_beta3,
623
523
                         subp->sub4_18.d_A1, subp->sub4_18.d_A0,
624
523
                         (long long)subp->sub4_18.t_tot, subp->sub4_18.WNt,
625
523
                         subp->sub4_18.leap, subp->sub4_18.WNlsf,
626
523
                         subp->sub4_18.DN, subp->sub4_18.lsf);
627
628
                /* notify the leap seconds correction in the end
629
                 * of current day */
630
                // IS-GPS-200, paragraph 20.3.3.5.2.4
631
                // FIXME: only allow LEAPs in June and December
632
                // only need to check whole seconds
633
523
                if (((session->context->gps_week % 256) ==
634
523
                     (unsigned short)subp->sub4_18.WNlsf) &&
635
292
                    (((subp->sub4_18.DN - 1) * SECS_PER_DAY) <
636
292
                     session->context->gps_tow.tv_sec) &&
637
212
                    ((subp->sub4_18.DN * SECS_PER_DAY) >
638
212
                     session->context->gps_tow.tv_sec)) {
639
640
106
                   if (subp->sub4_18.leap < subp->sub4_18.lsf) {
641
73
                        session->context->leap_notify = LEAP_ADDSECOND;
642
73
                   } else if (subp->sub4_18.leap > subp->sub4_18.lsf) {
643
6
                        session->context->leap_notify = LEAP_DELSECOND;
644
27
                   } else {
645
27
                        session->context->leap_notify = LEAP_NOWARNING;
646
27
                   }
647
417
                } else {
648
417
                   session->context->leap_notify = LEAP_NOWARNING;
649
417
                }
650
651
523
                session->context->leap_seconds = (int)subp->sub4_18.leap;
652
523
                session->context->valid |= LEAP_SECOND_VALID;
653
523
                break;
654
655
0
            case 57:    // aka pages 1, 6, 11, 16, 21
656
                /* for some inscutable reason these pages are all sent
657
                 * as page 57, IS-GPS-200 Table 20-V
658
                 * reserved */
659
0
                break;
660
661
0
            case 59:         // aka page 20
662
                /* for some inscrutable reason page 20 is sent
663
                 * as page 59, IS-GPS-200 Table 20-V
664
                 * reserved page */
665
0
                break;
666
667
0
            case 60:         // aka page 22
668
                /* for some inscrutable reason page 22 is sent
669
                 * as page 60, IS-GPS-200 Table 20-V */
670
                // reserved page
671
0
                break;
672
673
0
            case 61:         // aka page 23
674
                /* for some inscrutable reason page 23 is sent
675
                 * as page 61, IS-GPS-200 Table 20-V */
676
                // reserved page
677
0
                break;
678
679
0
            case 62:     // aka pages 12 and 24
680
                /* for some inscrutable reason these pages are all sent
681
                 * as page 62, IS-GPS-200 Table 20-V
682
                 * reserved */
683
0
                break;
684
685
86
            case 63:          // aka page 25
686
                /* for some inscrutable reason page 25 is sent
687
                 * as page 63, IS-GPS-200 Table 20-V */
688
                /* A-S flags/SV configurations for 32 SVs,
689
                 * plus SV health for SV 25 through 32
690
                 */
691
692
86
                sv = -1;
693
86
                subp->sub4_25.svf[1] = (unsigned char)((words[2] >> 12) &
694
86
                                                       BITMASK(4));
695
86
                subp->sub4_25.svf[2] = (unsigned char)((words[2] >>  8) &
696
86
                                                       BITMASK(4));
697
86
                subp->sub4_25.svf[3] = (unsigned char)((words[2] >>  4) &
698
86
                                                       BITMASK(4));
699
86
                subp->sub4_25.svf[4] = (unsigned char)((words[2] >>  0) &
700
86
                                                       BITMASK(4));
701
86
                subp->sub4_25.svf[5] = (unsigned char)((words[3] >> 20) &
702
86
                                                       BITMASK(4));
703
86
                subp->sub4_25.svf[6] = (unsigned char)((words[3] >> 16) &
704
86
                                                       BITMASK(4));
705
86
                subp->sub4_25.svf[7] = (unsigned char)((words[3] >> 12) &
706
86
                                                       BITMASK(4));
707
86
                subp->sub4_25.svf[8] = (unsigned char)((words[3] >>  8) &
708
86
                                                       BITMASK(4));
709
86
                subp->sub4_25.svf[9] = (unsigned char)((words[3] >>  4) &
710
86
                                                       BITMASK(4));
711
86
                subp->sub4_25.svf[10] = (unsigned char)((words[3] >> 0) &
712
86
                                                       BITMASK(4));
713
86
                subp->sub4_25.svf[11] = (unsigned char)((words[4] >> 20) &
714
86
                                                       BITMASK(4));
715
86
                subp->sub4_25.svf[12] = (unsigned char)((words[4] >> 16) &
716
86
                                                       BITMASK(4));
717
86
                subp->sub4_25.svf[13] = (unsigned char)((words[4] >> 12) &
718
86
                                                       BITMASK(4));
719
86
                subp->sub4_25.svf[14] = (unsigned char)((words[4] >> 8) &
720
86
                                                       BITMASK(4));
721
86
                subp->sub4_25.svf[15] = (unsigned char)((words[4] >> 4) &
722
86
                                                       BITMASK(4));
723
86
                subp->sub4_25.svf[16] = (unsigned char)((words[4] >> 0) &
724
86
                                                       BITMASK(4));
725
86
                subp->sub4_25.svf[17] = (unsigned char)((words[5] >> 20) &
726
86
                                                       BITMASK(4));
727
86
                subp->sub4_25.svf[18] = (unsigned char)((words[5] >> 16) &
728
86
                                                       BITMASK(4));
729
86
                subp->sub4_25.svf[19] = (unsigned char)((words[5] >> 12) &
730
86
                                                       BITMASK(4));
731
86
                subp->sub4_25.svf[20] = (unsigned char)((words[5] >> 8) &
732
86
                                                       BITMASK(4));
733
86
                subp->sub4_25.svf[21] = (unsigned char)((words[5] >> 4) &
734
86
                                                       BITMASK(4));
735
86
                subp->sub4_25.svf[22] = (unsigned char)((words[5] >> 0) &
736
86
                                                       BITMASK(4));
737
86
                subp->sub4_25.svf[23] = (unsigned char)((words[6] >> 20) &
738
86
                                                       BITMASK(4));
739
86
                subp->sub4_25.svf[24] = (unsigned char)((words[6] >> 16) &
740
86
                                                       BITMASK(4));
741
86
                subp->sub4_25.svf[25] = (unsigned char)((words[6] >> 12) &
742
86
                                                       BITMASK(4));
743
86
                subp->sub4_25.svf[26] = (unsigned char)((words[6] >> 8) &
744
86
                                                       BITMASK(4));
745
86
                subp->sub4_25.svf[27] = (unsigned char)((words[6] >> 4) &
746
86
                                                       BITMASK(4));
747
86
                subp->sub4_25.svf[28] = (unsigned char)((words[6] >> 0) &
748
86
                                                       BITMASK(4));
749
86
                subp->sub4_25.svf[29] = (unsigned char)((words[7] >> 20) &
750
86
                                                       BITMASK(4));
751
86
                subp->sub4_25.svf[30] = (unsigned char)((words[7] >> 16) &
752
86
                                                       BITMASK(4));
753
86
                subp->sub4_25.svf[31] = (unsigned char)((words[7] >> 12) &
754
86
                                                       BITMASK(4));
755
86
                subp->sub4_25.svf[32] = (unsigned char)((words[7] >> 8) &
756
86
                                                       BITMASK(4));
757
758
86
                subp->sub4_25.svhx[0] = ((words[7] >>  0) & BITMASK(6));
759
86
                subp->sub4_25.svhx[1] = ((words[8] >> 18) & BITMASK(6));
760
86
                subp->sub4_25.svhx[2] = ((words[8] >> 12) & BITMASK(6));
761
86
                subp->sub4_25.svhx[3] = ((words[8] >>  6) & BITMASK(6));
762
86
                subp->sub4_25.svhx[4] = ((words[8] >>  0) & BITMASK(6));
763
86
                subp->sub4_25.svhx[5] = ((words[9] >> 18) & BITMASK(6));
764
86
                subp->sub4_25.svhx[6] = ((words[9] >> 12) & BITMASK(6));
765
86
                subp->sub4_25.svhx[7] = ((words[9] >>  6) & BITMASK(6));
766
767
86
                GPSD_LOG(LOG_PROG, &session->context->errout,
768
86
                         "SUB,GPS: SF:4-25 data_id %d "
769
86
                         "SV1:%u SV2:%u SV3:%u SV4:%u "
770
86
                         "SV5:%u SV6:%u SV7:%u SV8:%u "
771
86
                         "SV9:%u SV10:%u SV11:%u SV12:%u "
772
86
                         "SV13:%u SV14:%u SV15:%u SV16:%u "
773
86
                         "SV17:%u SV18:%u SV19:%u SV20:%u "
774
86
                         "SV21:%u SV22:%u SV23:%u SV24:%u "
775
86
                         "SV25:%u SV26:%u SV27:%u SV28:%u "
776
86
                         "SV29:%u SV30:%u SV31:%u SV32:%u "
777
86
                         "SVH25:%u SVH26:%u SVH27:%u SVH28:%u "
778
86
                         "SVH29:%u SVH30:%u SVH31:%u SVH32:%u\n",
779
86
                         subp->data_id,
780
86
                         subp->sub4_25.svf[1],  subp->sub4_25.svf[2],
781
86
                         subp->sub4_25.svf[3],  subp->sub4_25.svf[4],
782
86
                         subp->sub4_25.svf[5],  subp->sub4_25.svf[6],
783
86
                         subp->sub4_25.svf[7],  subp->sub4_25.svf[8],
784
86
                         subp->sub4_25.svf[9],  subp->sub4_25.svf[10],
785
86
                         subp->sub4_25.svf[11], subp->sub4_25.svf[12],
786
86
                         subp->sub4_25.svf[13], subp->sub4_25.svf[14],
787
86
                         subp->sub4_25.svf[15], subp->sub4_25.svf[16],
788
86
                         subp->sub4_25.svf[17], subp->sub4_25.svf[18],
789
86
                         subp->sub4_25.svf[19], subp->sub4_25.svf[20],
790
86
                         subp->sub4_25.svf[21], subp->sub4_25.svf[22],
791
86
                         subp->sub4_25.svf[23], subp->sub4_25.svf[24],
792
86
                         subp->sub4_25.svf[25], subp->sub4_25.svf[26],
793
86
                         subp->sub4_25.svf[27], subp->sub4_25.svf[28],
794
86
                         subp->sub4_25.svf[29], subp->sub4_25.svf[30],
795
86
                         subp->sub4_25.svf[31], subp->sub4_25.svf[32],
796
86
                         subp->sub4_25.svhx[0], subp->sub4_25.svhx[1],
797
86
                         subp->sub4_25.svhx[2], subp->sub4_25.svhx[3],
798
86
                         subp->sub4_25.svhx[4], subp->sub4_25.svhx[5],
799
86
                         subp->sub4_25.svhx[6], subp->sub4_25.svhx[7]);
800
86
                break;
801
802
100
            default:                    // unknown page...
803
100
                ;                       // no op
804
2.23k
            }
805
2.23k
            if ( -1 < sv ) {
806
759
                subp->is_almanac = 1;
807
759
                subframe_almanac(&session->context->errout,
808
759
                                 subp->tSVID, words, subp->subframe_num,
809
759
                                 (uint8_t)sv, subp->data_id,
810
759
                                 &subp->sub4.almanac);
811
1.47k
            } else if ( -2 == sv ) {
812
                // unknown or secret page
813
100
                GPSD_LOG(LOG_PROG, &session->context->errout,
814
100
                         "SUB,GPS: SF:4-%d data_id %d\n",
815
100
                         subp->pageid, subp->data_id);
816
100
                return 0;
817
100
            }
818
            // else, already handled
819
2.23k
        }
820
2.13k
        break;
821
2.13k
    case 5:
822
        /* Pages 0, dummy almanac for dummy SV 0
823
         * Pages 1 through 24: almanac data for SV 1 through 24
824
         * Page 25: SV health data for SV 1 through 24, the almanac
825
         * reference time, the almanac reference week number.
826
         */
827
238
        if (25 > subp->pageid) {
828
94
            subp->is_almanac = 1;
829
94
            subframe_almanac(&session->context->errout,
830
94
                             subp->tSVID, words, subp->subframe_num,
831
94
                             subp->pageid, subp->data_id, &subp->sub5.almanac);
832
144
        } else if (51 == subp->pageid) {
833
            /* for some inscrutable reason page 25 is sent as page 51
834
             * IS-GPS-200 Table 20-V */
835
836
70
            subp->sub5_25.toa   = ((words[2] >> 8) & BITMASK(8));
837
70
            subp->sub5_25.l_toa = (long)subp->sub5_25.toa << 12;
838
70
            subp->sub5_25.WNa   = (words[2] & BITMASK(8));
839
70
            subp->sub5_25.sv[1] = ((words[3] >> 18) & BITMASK(6));
840
70
            subp->sub5_25.sv[2] = ((words[3] >> 12) & BITMASK(6));
841
70
            subp->sub5_25.sv[3] = ((words[3] >>  6) & BITMASK(6));
842
70
            subp->sub5_25.sv[4] = ((words[3] >>  0) & BITMASK(6));
843
70
            subp->sub5_25.sv[5] = ((words[4] >> 18) & BITMASK(6));
844
70
            subp->sub5_25.sv[6] = ((words[4] >> 12) & BITMASK(6));
845
70
            subp->sub5_25.sv[7] = ((words[4] >>  6) & BITMASK(6));
846
70
            subp->sub5_25.sv[8] = ((words[4] >>  0) & BITMASK(6));
847
70
            subp->sub5_25.sv[9] = ((words[5] >> 18) & BITMASK(6));
848
70
            subp->sub5_25.sv[10] = ((words[5] >> 12) & BITMASK(6));
849
70
            subp->sub5_25.sv[11] = ((words[5] >>  6) & BITMASK(6));
850
70
            subp->sub5_25.sv[12] = ((words[5] >>  0) & BITMASK(6));
851
70
            subp->sub5_25.sv[13] = ((words[6] >> 18) & BITMASK(6));
852
70
            subp->sub5_25.sv[14] = ((words[6] >> 12) & BITMASK(6));
853
70
            subp->sub5_25.sv[15] = ((words[6] >>  6) & BITMASK(6));
854
70
            subp->sub5_25.sv[16] = ((words[6] >>  0) & BITMASK(6));
855
70
            subp->sub5_25.sv[17] = ((words[7] >> 18) & BITMASK(6));
856
70
            subp->sub5_25.sv[18] = ((words[7] >> 12) & BITMASK(6));
857
70
            subp->sub5_25.sv[19] = ((words[7] >>  6) & BITMASK(6));
858
70
            subp->sub5_25.sv[20] = ((words[7] >>  0) & BITMASK(6));
859
70
            subp->sub5_25.sv[21] = ((words[8] >> 18) & BITMASK(6));
860
70
            subp->sub5_25.sv[22] = ((words[8] >> 12) & BITMASK(6));
861
70
            subp->sub5_25.sv[23] = ((words[8] >>  6) & BITMASK(6));
862
70
            subp->sub5_25.sv[24] = ((words[8] >>  0) & BITMASK(6));
863
70
            GPSD_LOG(LOG_PROG, &session->context->errout,
864
70
                     "SUB,GPS: SF:5-25 SV:%2u ID:%u toa:%lu WNa:%u "
865
70
                     "SV1:%u SV2:%u SV3:%u SV4:%u "
866
70
                     "SV5:%u SV6:%u SV7:%u SV8:%u "
867
70
                     "SV9:%u SV10:%u SV11:%u SV12:%u "
868
70
                     "SV13:%u SV14:%u SV15:%u SV16:%u "
869
70
                     "SV17:%u SV18:%u SV19:%u SV20:%u "
870
70
                     "SV21:%u SV22:%u SV23:%u SV24:%u\n",
871
70
                     subp->tSVID, subp->data_id,
872
70
                     subp->sub5_25.l_toa, subp->sub5_25.WNa,
873
70
                     subp->sub5_25.sv[1], subp->sub5_25.sv[2],
874
70
                     subp->sub5_25.sv[3], subp->sub5_25.sv[4],
875
70
                     subp->sub5_25.sv[5], subp->sub5_25.sv[6],
876
70
                     subp->sub5_25.sv[7], subp->sub5_25.sv[8],
877
70
                     subp->sub5_25.sv[9], subp->sub5_25.sv[10],
878
70
                     subp->sub5_25.sv[11], subp->sub5_25.sv[12],
879
70
                     subp->sub5_25.sv[13], subp->sub5_25.sv[14],
880
70
                     subp->sub5_25.sv[15], subp->sub5_25.sv[16],
881
70
                     subp->sub5_25.sv[17], subp->sub5_25.sv[18],
882
70
                     subp->sub5_25.sv[19], subp->sub5_25.sv[20],
883
70
                     subp->sub5_25.sv[21], subp->sub5_25.sv[22],
884
70
                     subp->sub5_25.sv[23], subp->sub5_25.sv[24]);
885
74
        } else {
886
            // unknown page
887
74
            GPSD_LOG(LOG_PROG, &session->context->errout,
888
74
                     "SUB,GPS: SF:5-%d data_id %d unknown page\n",
889
74
                     subp->pageid, subp->data_id);
890
74
            return 0;
891
74
        }
892
164
        break;
893
164
    default:
894
        // unknown/illegal subframe
895
79
        return 0;
896
2.97k
    }
897
2.71k
    return SUBFRAME_SET;
898
2.97k
}
899
900
static gps_mask_t almanac_bds(uint32_t words[], struct subframe_t *subp)
901
0
{
902
0
    int64_t tmp;
903
0
    gps_mask_t mask = SUBFRAME_SET;
904
905
0
    tmp = ((words[1] >> 8) & 3) << 22;
906
0
    tmp |= (words[2] >> 8) & BITMASK(22);
907
0
    if (0 == tmp) {
908
        // it happens
909
0
        return 0;
910
0
    }
911
0
    subp->orbit.sqrtA = tmp * pow(2.0, -11);
912
0
    if (2600 > subp->orbit.sqrtA) {
913
        // Sanity check: A must be greater than Earth radius
914
0
        return 0;
915
0
    }
916
917
0
    tmp = (words[3] >> 19) & BITMASK(11);                     // a1 (af1)
918
0
    tmp = UINT2INT(tmp, 11);
919
0
    subp->orbit.af1 = tmp * pow(2.0, -38);
920
921
0
    tmp = (words[3] >> 8) & BITMASK(11);                      // a0 (af0)
922
0
    tmp = UINT2INT(tmp, 11);
923
0
    subp->orbit.af0 = tmp * pow(2.0, -20);
924
925
0
    tmp = ((words[4] >> 8) & BITMASK(22)) << 2;               // Omega0
926
0
    tmp |= (words[5] >> 28) & 3;
927
0
    tmp = UINT2INT(tmp, 24);
928
0
    subp->orbit.Omega0 = tmp * pow(2.0, -23);
929
930
0
    tmp = (words[5] >> 11) & BITMASK(17);                     // e
931
0
    subp->orbit.eccentricity = tmp * pow(2.0, -21);
932
933
0
    tmp = ((words[5] >> 8) & BITMASK(3)) << 13;
934
0
    tmp |= (words[6] >> 17) & BITMASK(13);
935
0
    tmp = UINT2INT(tmp, 16);
936
0
    subp->orbit.deltai = tmp * pow(2.0, -19);
937
    // also convert deltai to i0
938
0
    if ((1 <= subp->orbit.sv && 6 >= subp->orbit.sv) ||
939
0
        (59 <= subp->orbit.sv && 63 >= subp->orbit.sv)) {
940
        // GEO sats add 0
941
0
        subp->orbit.i0 = subp->orbit.deltai;
942
0
    } else {
943
        // MEO/IGSO adding 0.30
944
0
        subp->orbit.i0 = subp->orbit.deltai + 0.30;
945
0
    }
946
947
0
    subp->orbit.toa = ((words[6] >> 9) & BITMASK(8)) << 12;   // toa
948
949
0
    tmp = ((words[6] >> 8) & 1) << 16;                        // Omegad
950
0
    tmp |= (words[7] >> 14) & BITMASK(16);
951
0
    tmp = UINT2INT(tmp, 17);
952
0
    subp->orbit.Omegad = tmp * pow(2.0, -38);
953
954
0
    tmp = ((words[7] >> 8) & BITMASK(6)) << 18;               // omega
955
0
    tmp |= (words[8] >> 12) & BITMASK(18);
956
0
    tmp = UINT2INT(tmp, 24);
957
0
    subp->orbit.omega = tmp * pow(2.0, -23);
958
959
0
    tmp = ((words[8] >> 8) & BITMASK(4)) << 20;               // M0
960
0
    tmp |= (words[9] >> 10) & BITMASK(20);
961
0
    tmp = UINT2INT(tmp, 24);
962
0
    subp->orbit.M0 = tmp * pow(2.0, -23);
963
0
    return mask;
964
0
}
965
966
// Code to decode BeiDou Subframes
967
968
/* Code to decode BeiDou Subframes sigId 6
969
 */
970
static gps_mask_t subframe_bds6(struct gps_device_t *session,
971
                               unsigned int sigId UNUSED,
972
                               unsigned int tSVID UNUSED,
973
                               uint32_t words[] UNUSED,
974
                               unsigned int numwords)
975
0
{
976
0
    gps_mask_t mask = 0;
977
978
0
    switch (numwords) {
979
0
    case 3:
980
        // Subframe 1, 72 bits raw, 14 bits encoded
981
        // unclear what u-blox did to get 3 32-bit words.
982
0
        {
983
0
            unsigned PRN = (words[0] >> 26) & BITMASK(6);
984
0
            unsigned SOH = (words[0] & 0x0ff) * 18;          // WAG????
985
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
986
0
                 "SUB B-CNAV1  1: PRN %u SOH %u\n", PRN, SOH);
987
0
        }
988
0
        break;
989
0
    case 19:
990
        // Subframe 2, 600 bits + 8 bits padding == 19 32-bit words
991
0
        {
992
0
            unsigned WN = (words[0] >> 19) & BITMASK(13);
993
0
            unsigned HOW = (words[0] & 0x0ff) * 18;          // WAG????
994
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
995
0
                 "SUB B-CNAV1  2: WN %u HOW %u\n", WN, HOW);
996
0
        }
997
0
        break;
998
0
    case 9:
999
        // Subframe 3, 264 bits + 24 bits padding == 9 32-bit words
1000
0
        {
1001
            // PageID   1,2,4,5, and 60
1002
0
            unsigned PageID = (words[0] >> 26) & BITMASK(6);
1003
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
1004
0
                 "SUB B-CNAV1  3: PageId %u\n", PageID);
1005
0
        }
1006
0
        break;
1007
0
    default:
1008
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1009
0
                 "SUB subframe_bds6: numwords %u ??\n", numwords);
1010
0
        break;
1011
0
    }
1012
1013
1014
0
    return mask;
1015
0
}
1016
1017
/* Code to decode BeiDou Subframes sigId 8
1018
 *
1019
 * BDS B2 ad, B-CNAV2
1020
 */
1021
static gps_mask_t subframe_bds8(struct gps_device_t *session,
1022
                               unsigned int sigId UNUSED,
1023
                               unsigned int tSVID UNUSED,
1024
                               uint32_t words[],
1025
                               unsigned int numwords UNUSED)
1026
0
{
1027
0
    gps_mask_t mask = 0;
1028
0
    unsigned PRN = (words[0] >> 26) & BITMASK(6);
1029
0
    unsigned mtype = (words[0] >> 20) & BITMASK(6);
1030
0
    long unsigned SOW = (words[0] >> 2) & BITMASK(18);
1031
0
    unsigned HS = words[0] & BITMASK(2);
1032
1033
    // common parts
1034
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1035
0
             "SUB subframe_bds8: PRN %u mtype %u SOW %lu\n",
1036
0
              PRN, mtype, SOW);
1037
1038
0
    switch (mtype) {
1039
0
    case 10:    // Ephemeris 1
1040
0
        {
1041
0
            unsigned WN = (((words[0] & BITMASK(2)) << 11) |
1042
0
                          ((words[1] >> 21) & BITMASK(11)));
1043
0
            GPSD_LOG(LOG_PROG, &session->context->errout,
1044
0
                     "SUB WN %u\n", WN);
1045
0
        }
1046
0
        break;
1047
0
    case 11:
1048
0
        FALLTHROUGH
1049
0
    case 39:
1050
0
        FALLTHROUGH
1051
0
    case 31:
1052
0
        FALLTHROUGH
1053
0
    case 12:
1054
0
        FALLTHROUGH
1055
0
    case 13:
1056
0
        FALLTHROUGH
1057
0
    case 14:
1058
0
        FALLTHROUGH
1059
0
    case 40:
1060
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1061
0
                 "SUB HS %u\n", HS);
1062
0
        break;
1063
0
    default:
1064
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1065
0
                 "SUB unhandled mtype %u\n", mtype);
1066
0
        break;
1067
0
    }
1068
1069
0
    return mask;
1070
0
}
1071
1072
/* Code to decode BeiDou Subframes
1073
 *
1074
 * Needs work.
1075
 *
1076
 * http://en.beidou.gov.cn/SYSTEMS/ICD/
1077
 * BeiDou Interface Control Document v1.0
1078
 * See u-blox8-M8_ReceiverDescrProtSpec_UBX-13003221.pdf
1079
 * Section 10.4 BeiDou
1080
 * or
1081
 * ZED-F9P_IntegrationManual_(UBX-18010802).pdf
1082
 * Section 3.13.1.4 BeiDou
1083
 * gotta decode the u-blox munging and the BeiDou packing...
1084
 *
1085
 * use https://galmon.eu to verify Ephemeris
1086
 *
1087
 * 10 words.  ignore top 2 bits, so 30 bits.  The 8 LSB are parity.
1088
 * except words[0] is 4 parity
1089
 */
1090
static gps_mask_t subframe_bds(struct gps_device_t *session,
1091
                               unsigned int sigId UNUSED,
1092
                               unsigned int tSVID UNUSED,
1093
                               uint32_t words[],
1094
                               unsigned int numwords UNUSED)
1095
0
{
1096
0
    gps_mask_t mask = 0;
1097
0
    char *word_desc = "";
1098
0
    unsigned FraID = (words[0] >> 12) & 7;
1099
0
    unsigned SOW;
1100
0
    struct subframe_t *subp = &session->gpsdata.subframe;
1101
0
    int64_t tmp;
1102
1103
0
    switch (sigId) {
1104
0
    case 0:
1105
        // 10 == numwords. We know this one.
1106
0
        break;
1107
0
    case 6:
1108
        // BDS B1 Cd, 3, 9, 19 == numwords. B-CNAV1
1109
0
        return subframe_bds6(session, sigId, tSVID, words, numwords);
1110
1111
0
    case 8:
1112
        // BDS B2 ad , 9 == numwords. We know this one.
1113
0
        return subframe_bds8(session, sigId, tSVID, words, numwords);
1114
1115
0
    default:
1116
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
1117
0
                 "SUB subframe_bds: Can't handle sigId %u\n", sigId);
1118
0
        return mask;
1119
0
    }
1120
1121
    // The plain sigId == 0 case.
1122
0
    init_subframe(&session->gpsdata.subframe, GNSSID_BD, (uint8_t)tSVID);
1123
0
    subp->subframe_num = FraID;
1124
1125
0
    SOW = ((words[0] >> 4) & BITMASK(8)) << 12;
1126
0
    SOW |= (words[1] >> 18) & BITMASK(12);
1127
0
    subp->TOW17 = SOW;
1128
1129
0
    GPSD_LOG(LOG_DATA, &session->context->errout,
1130
0
             "SUB,BDS: len %u: "
1131
0
             "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
1132
0
             numwords,
1133
0
             words[0], words[1], words[2], words[3], words[4],
1134
0
             words[5], words[6], words[7], words[8], words[9]);
1135
1136
0
    switch (FraID) {
1137
0
    case 1:
1138
0
        word_desc = "Ephemeris 1";
1139
0
        subp->orbit.sv = tSVID;
1140
        // subp->SatH1 = (words[1] >> 17) & 1;
1141
0
        subp->orbit.AODC = (words[1] >> 12) & BITMASK(5);     // AODC
1142
0
        subp->orbit.URAI = (words[1] >> 8) & BITMASK(4);
1143
0
        subp->WN = (words[2] >> 17) & BITMASK(13);            // WN
1144
0
        subp->orbit.WN = subp->WN;
1145
0
        subp->orbit.toc = ((words[2] >> 8) & BITMASK(9)) << 8;  // toc
1146
0
        subp->orbit.toc |= (words[3] >> 22) & BITMASK(8);
1147
0
        subp->orbit.toc <<= 3;
1148
1149
0
        tmp = (words[3] >> 12) & BITMASK(10);                 // TGD1
1150
0
        subp->orbit.TGD1 = UINT2INT(tmp, 10) * 0.1;
1151
1152
0
        tmp = ((words[3] >> 8) & BITMASK(4)) << 6;            // TGD2
1153
0
        tmp |= (words[4] >> 24) & BITMASK(6);
1154
0
        subp->orbit.TGD2 = UINT2INT(tmp, 10) * 0.1;
1155
1156
0
        tmp = (words[4] >> 16) & BITMASK(8);                  // alpha0
1157
0
        tmp = UINT2INT(tmp, 8);
1158
0
        subp->orbit.alpha0 = tmp * pow(2.0, -30);
1159
1160
0
        tmp = (words[4] >> 8) & BITMASK(8);                   // alpha1
1161
0
        tmp = UINT2INT(tmp, 8);
1162
0
        subp->orbit.alpha1 = tmp * pow(2.0, -27);
1163
1164
0
        tmp = (words[5] >> 22) & BITMASK(8);                  // alpha2
1165
0
        tmp = UINT2INT(tmp, 8);
1166
0
        subp->orbit.alpha2 = tmp * pow(2.0, -24);
1167
1168
0
        tmp = (words[5] >> 14) & BITMASK(8);                  // alpha3
1169
0
        tmp = UINT2INT(tmp, 8);
1170
0
        subp->orbit.alpha3 = tmp * pow(2.0, -24);
1171
1172
0
        tmp = ((words[4] >> 8) & BITMASK(6)) << 2;            // beta0
1173
0
        tmp |= (words[5] >> 28) & 3;
1174
0
        tmp = UINT2INT(tmp, 8);
1175
0
        subp->orbit.beta0 = tmp << 14;
1176
1177
0
        tmp = (words[5] >> 20) & BITMASK(8);                  // beta1
1178
0
        tmp = UINT2INT(tmp, 8);
1179
0
        subp->orbit.beta1 = tmp << 14;
1180
1181
0
        tmp = (words[5] >> 12) & BITMASK(8);                  // beta2
1182
0
        tmp = UINT2INT(tmp, 8);
1183
0
        subp->orbit.beta2 = tmp << 16;
1184
1185
0
        tmp = ((words[5] >> 8) & BITMASK(4)) << 4;            // beta3
1186
0
        tmp |= (words[6] >> 26) & BITMASK(4);
1187
0
        tmp = UINT2INT(tmp, 8);
1188
0
        subp->orbit.beta3 = tmp << 16;
1189
1190
0
        tmp = (words[6] >> 15) & BITMASK(11);                 // a2 (af2)
1191
0
        tmp = UINT2INT(tmp, 11);
1192
0
        subp->orbit.af2 = tmp * pow(2.0, -66);
1193
1194
0
        tmp = ((words[7] >> 8) & BITMASK(7)) << 17;           // a0 (af0)
1195
0
        tmp |= (words[8] >> 13) & BITMASK(17);
1196
0
        tmp = UINT2INT(tmp, 24);
1197
0
        subp->orbit.af0 = tmp * pow(2.0, -33);
1198
1199
0
        tmp = ((words[8] >> 8) & BITMASK(5)) << 17;           // a1 (af1)
1200
0
        tmp |= (words[9] >> 13) & BITMASK(17);
1201
0
        tmp = UINT2INT(tmp, 22);
1202
0
        subp->orbit.af1 = tmp * pow(2.0, -50);
1203
1204
0
        subp->orbit.AODE = (words[8] >> 8) & BITMASK(5);      // AODE
1205
0
        subp->is_almanac = SUBFRAME_ORBIT;
1206
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1207
0
        mask = SUBFRAME_SET;
1208
0
        break;
1209
0
    case 2:
1210
0
        word_desc = "Ephemeris 2";
1211
0
        mask = SUBFRAME_SET;
1212
0
        subp->is_almanac = SUBFRAME_ORBIT;
1213
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1214
1215
0
        tmp = ((words[1] >> 8) & BITMASK(10)) << 6;           // deltan
1216
0
        tmp |= (words[2] >> 24) & BITMASK(6);
1217
0
        tmp = UINT2INT(tmp, 16);
1218
0
        subp->orbit.deltan = tmp * pow(2.0, -43);
1219
1220
0
        tmp = ((words[2] >> 8) & BITMASK(16)) << 2;           // Cuc
1221
0
        tmp |= (words[3] >> 28) & BITMASK(2);
1222
0
        tmp = UINT2INT(tmp, 18);
1223
0
        subp->orbit.Cuc = tmp * pow(2.0, -31);
1224
1225
0
        tmp = ((words[3] >> 8) & BITMASK(20)) << 12;          // M0
1226
0
        tmp |= (words[4] >> 18) & BITMASK(12);
1227
0
        tmp = UINT2INT(tmp, 32);
1228
0
        subp->orbit.M0 = tmp * pow(2.0, -31);
1229
1230
0
        tmp = ((words[4] >> 8) & BITMASK(10)) << 22;          // e
1231
0
        tmp |= (words[5] >> 8) & BITMASK(22);
1232
0
        subp->orbit.eccentricity = tmp * pow(2.0, -33);
1233
1234
0
        tmp = (words[6] >> 12) & BITMASK(18);                 // Cus
1235
0
        tmp = UINT2INT(tmp, 18);
1236
0
        subp->orbit.Cus = tmp * pow(2.0, -31);
1237
1238
0
        tmp = ((words[6] >> 8) & BITMASK(4)) << 14;           // Crc
1239
0
        tmp |= (words[7] >> 16) & BITMASK(14);
1240
0
        tmp = UINT2INT(tmp, 18);
1241
0
        subp->orbit.Crc = tmp * pow(2.0, -6);
1242
1243
0
        tmp = ((words[7] >> 8) & BITMASK(8)) << 10;           // Crs
1244
0
        tmp |= (words[8] >> 20) & BITMASK(10);
1245
0
        tmp = UINT2INT(tmp, 18);
1246
0
        subp->orbit.Crs = tmp * pow(2.0, -6);
1247
1248
0
        tmp = ((words[8] >> 8) & BITMASK(12)) << 20;          // sqrtA
1249
0
        tmp |= (words[9] >> 10) & BITMASK(20);
1250
0
        subp->orbit.sqrtA = tmp * pow(2.0, -19);
1251
0
        if (2600 > subp->orbit.sqrtA) {
1252
            // Sanity check: A must be greater than Earth radius
1253
0
            mask = 0;
1254
0
        }
1255
1256
0
        tmp = (words[9] >> 8) & 3;                            // toe MSBs
1257
0
        subp->orbit.toeMSB = tmp << 18;
1258
1259
0
        break;
1260
0
    case 3:
1261
0
        word_desc = "Ephemeris 3";
1262
0
        subp->is_almanac = SUBFRAME_ORBIT;
1263
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1264
1265
0
        tmp = ((words[1] >> 8) & BITMASK(10)) << 5;           // toeLSB
1266
0
        tmp |= (words[2] >> 25) & BITMASK(5);
1267
0
        subp->orbit.toeLSB = tmp << 3;
1268
1269
0
        tmp = ((words[2] >> 8) & BITMASK(17)) << 15;          // i0
1270
0
        tmp |= (words[3] >> 15) & BITMASK(15);
1271
0
        tmp = UINT2INT(tmp, 32);
1272
0
        subp->orbit.i0 = tmp * pow(2.0, -31);
1273
1274
0
        tmp = ((words[3] >> 8) & BITMASK(7)) << 11;           // Cic
1275
0
        tmp |= (words[4] >> 19) & BITMASK(11);
1276
0
        tmp = UINT2INT(tmp, 18);
1277
0
        subp->orbit.Cic = tmp * pow(2.0, -31);
1278
1279
0
        tmp = ((words[4] >> 8) & BITMASK(11)) << 13;          // Omegad
1280
0
        tmp |= (words[5] >> 17) & BITMASK(13);
1281
0
        tmp = UINT2INT(tmp, 24);
1282
0
        subp->orbit.Omegad = tmp * pow(2.0, -43);
1283
1284
0
        tmp = ((words[5] >> 8) & BITMASK(9)) << 9;            // Cis
1285
0
        tmp |= (words[6] >> 21) & BITMASK(9);
1286
0
        tmp = UINT2INT(tmp, 18);
1287
0
        subp->orbit.Cis = tmp * pow(2.0, -31);
1288
1289
0
        tmp = ((words[6] >> 8) & BITMASK(13)) << 1;           // IDOT
1290
0
        tmp |= (words[7] >> 29) & 1;
1291
0
        tmp = UINT2INT(tmp, 14);
1292
0
        subp->orbit.IDOT = tmp * pow(2.0, -43);
1293
1294
0
        tmp = ((words[7] >> 8) & BITMASK(21)) << 11;          // Omega0
1295
0
        tmp |= (words[8] >> 19) & BITMASK(11);
1296
0
        tmp = UINT2INT(tmp, 32);
1297
0
        subp->orbit.Omega0 = tmp * pow(2.0, -31);
1298
1299
0
        tmp = ((words[8] >> 8) & BITMASK(11)) << 21;          // omega
1300
0
        tmp |= (words[9] >> 9) & BITMASK(21);
1301
0
        tmp = UINT2INT(tmp, 32);
1302
0
        subp->orbit.omega = tmp * pow(2.0, -31);
1303
1304
0
        mask = SUBFRAME_SET;
1305
0
        break;
1306
0
    case 4:
1307
0
        {
1308
0
            unsigned Pnum = (words[1] >> 10) & BITMASK(7);
1309
            // unsigned AmEpID = (words[9] >> 8) & 3; // unused, for now
1310
0
            if (1 <= Pnum && 24 >= Pnum) {
1311
0
                word_desc = "Almanac 1";
1312
0
                subp->is_almanac = SUBFRAME_ORBIT;
1313
0
                subp->orbit.type = ORBIT_ALMANAC;
1314
0
                subp->orbit.sv = Pnum;
1315
0
                mask = almanac_bds(words, subp);
1316
0
            } else {
1317
0
                word_desc = "Reserved";
1318
0
            }
1319
0
        }
1320
0
        break;
1321
0
    case 5:
1322
0
        {
1323
0
            unsigned Pnum = (words[1] >> 10) & BITMASK(7);
1324
0
            unsigned AmEpID = (words[9] >> 8) & 3;  // aka AmID
1325
0
            if (1 <= Pnum && 6 >= Pnum) {
1326
0
                if (3 == AmEpID) {
1327
0
                    word_desc = "Almanac 2";
1328
0
                    subp->is_almanac = SUBFRAME_ORBIT;
1329
0
                    subp->orbit.type = ORBIT_ALMANAC;
1330
0
                    subp->orbit.sv = Pnum + 24;
1331
0
                    mask =almanac_bds(words, subp);
1332
0
                } else {
1333
0
                    word_desc = "Reserved";
1334
0
                }
1335
0
            } else if (11 <= Pnum && 23 >= Pnum) {
1336
                // AmEpID is AmID
1337
0
                word_desc = "Almanac 2";
1338
0
                subp->is_almanac = SUBFRAME_ORBIT;
1339
0
                subp->orbit.type = ORBIT_ALMANAC;
1340
0
                switch (AmEpID) {
1341
0
                case 0:
1342
0
                    FALLTHROUGH
1343
0
                default:
1344
                    // reserved
1345
0
                    subp->orbit.sv = 0;
1346
0
                    break;
1347
0
                case 1:
1348
                    // 31 to 43
1349
0
                    subp->orbit.sv = Pnum + 20;
1350
0
                    break;
1351
0
                case 2:
1352
                    // 44 to 56
1353
0
                    subp->orbit.sv = Pnum + 33;
1354
0
                    break;
1355
0
                case 3:
1356
                    // 57 to 63
1357
0
                    subp->orbit.sv = Pnum + 46;
1358
0
                    if (63 < subp->orbit.sv) {
1359
0
                        subp->orbit.sv = 0;
1360
0
                    }
1361
0
                    break;
1362
0
                }
1363
0
                if (0 == subp->orbit.sv) {
1364
0
                    word_desc = "Reserved";
1365
0
                } else {
1366
0
                    mask = almanac_bds(words, subp);
1367
0
                }
1368
0
            } else if (7 == Pnum) {
1369
0
                word_desc = "Health 1";
1370
0
            } else if (8 == Pnum) {
1371
0
                word_desc = "Health 20";
1372
0
            } else if (9 == Pnum) {
1373
0
                word_desc = "GST-GPS";
1374
0
            } else if (10 == Pnum) {
1375
0
                word_desc = "GST-UTC";
1376
0
            } else {
1377
0
                word_desc = "Other";
1378
0
            }
1379
0
        }
1380
0
        break;
1381
0
    default:
1382
0
        word_desc = "Unknown FraID";
1383
0
        break;
1384
0
    }
1385
1386
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1387
0
             "SUB,BDS: FraID %u (%s) SOW %u\n",
1388
0
             FraID, word_desc, SOW);
1389
1390
0
    return mask;
1391
0
}
1392
1393
/* Stub of code to decode Galileo Subframes
1394
 *
1395
 * for now only handles the 8 word subframe.
1396
 *
1397
 * Galileo_OS_SIS_ICD_v2.0.pdf
1398
 * See u-blox8-M8_ReceiverDescrProtSpec_UBX-13003221.pdf
1399
 * Section 10.5 Galileo
1400
 * gotta decode the u-blox munging and the Galileo packing...
1401
 * porting to none u-blox will require separate mungin
1402
 *
1403
 * Current Galileo Ephemeris can be found here:
1404
 * https://cddis.gsfc.nasa.gov/Data_and_Derived_Products/GNSS/daily_gnss_l.html
1405
 *
1406
 * Current Galileo Almanac can be found here:
1407
 * https://www.gsc-europa.eu/product-almanacs
1408
 */
1409
static gps_mask_t subframe_gal(struct gps_device_t *session,
1410
                               unsigned int tSVID,
1411
                               uint32_t words[],
1412
                               unsigned int numwords)
1413
0
{
1414
0
    gps_mask_t mask = 0;
1415
0
    char *word_desc = "";
1416
    // always zero on E5b-I, always 1 on E1-B
1417
0
    unsigned even = words[0] >> 31;
1418
    // # zero for nominal page, one for alert page
1419
0
    unsigned page_type;
1420
0
    unsigned word_type;
1421
0
    struct subframe_t *subp;
1422
0
    long tmp;
1423
1424
0
    if (8 > numwords) {
1425
        // Later on there will be different lengths than 8.
1426
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1427
0
                 "SUB,GAL: expected 8 words, got %u\n",
1428
0
                 numwords);
1429
0
        return 0;
1430
0
    }
1431
0
    page_type = (words[0] >> 30) & 1;
1432
0
    word_type = (words[0] >> 24) & BITMASK(6);
1433
1434
0
    GPSD_LOG(LOG_DATA, &session->context->errout,
1435
0
             "SUB,GAL: tSVID %u len %u: "
1436
0
             "%08x %08x %08x %08x %08x %08x %08x %08x\n", tSVID, numwords,
1437
0
             words[0], words[1], words[2], words[3], words[4],
1438
0
             words[5], words[6], words[7]);
1439
1440
0
    if (1 == page_type) {
1441
        // Alerts pages are all "Reserved"
1442
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1443
0
                 "SUB,GAL: ignoring Alert Page \n");
1444
0
        return 0;
1445
0
    }
1446
0
    if (1 == even) {
1447
0
        GPSD_LOG(LOG_PROG, &session->context->errout,
1448
0
                 "SUB,GAL: page flipped?\n");
1449
0
        return 0;
1450
0
    }
1451
0
    subp = &session->gpsdata.subframe;
1452
0
    init_subframe(subp, GNSSID_GAL, (uint8_t)tSVID);
1453
0
    subp->subframe_num = word_type;
1454
0
    subp->pageid = word_type;
1455
1456
0
    switch (word_type) {
1457
0
    case 0:
1458
0
        word_desc = "Spare Word";
1459
0
        subp->orbit.sv = tSVID;
1460
0
        tmp = (words[0] >> 22) & BITMASK(2);
1461
0
        if (2 == tmp) {
1462
            // valid time
1463
0
            subp->WN = (words[3] >> 18) & BITMASK(12);        // WN
1464
0
            subp->TOW17 = ((words[3] >> 14) & BITMASK(4)) << 16;    // TOW
1465
0
            subp->TOW17 |= (words[4] >> 14) & BITMASK(16);
1466
0
            subp->is_almanac = SUBFRAME_ORBIT;
1467
0
            mask = SUBFRAME_SET;
1468
0
        }
1469
0
        break;
1470
0
    case 1:
1471
0
        word_desc = "Ephemeris 1";
1472
0
        mask = SUBFRAME_SET;
1473
0
        subp->orbit.sv = tSVID;
1474
0
        subp->orbit.IODE = (words[0] >> 14) & BITMASK(10);    // IODnav
1475
0
        subp->orbit.toe = (words[0] & BITMASK(14)) * 60;      // toe
1476
1477
0
        tmp = words[1] & BITMASK(32);                         // M0
1478
0
        tmp = UINT2INT(tmp, 32);
1479
0
        subp->orbit.M0 = tmp * pow(2.0, -31);
1480
1481
0
        tmp = words[2] & BITMASK(32);                         // e
1482
0
        subp->orbit.eccentricity = tmp * pow(2.0, -33);
1483
1484
0
        tmp = ((words[3] >> 14) & BITMASK(18)) << 14;         // sqrtA
1485
0
        tmp |= (words[4] >> 16) & BITMASK(14);
1486
0
        subp->orbit.sqrtA = tmp * pow(2.0, -19);
1487
0
        if (2600 > subp->orbit.sqrtA) {
1488
            // Sanity check: A must be greater than Earth radius
1489
0
            mask = 0;
1490
0
        }
1491
1492
0
        subp->is_almanac = SUBFRAME_ORBIT;
1493
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1494
0
        break;
1495
0
    case 2:
1496
0
        word_desc = "Ephemeris 2";
1497
0
        subp->orbit.sv = tSVID;
1498
0
        subp->orbit.IODE = (words[0] >> 14) & BITMASK(10);    // IODnav
1499
1500
0
        tmp = (words[0] & BITMASK(14)) << 18;                 // Omega0
1501
0
        tmp |= (words[1] >> 14) & BITMASK(18);
1502
0
        tmp = UINT2INT(tmp, 32);
1503
0
        subp->orbit.Omega0 = tmp * pow(2.0, -31);
1504
1505
0
        tmp = (words[1] & BITMASK(14)) << 18;                 // i0
1506
0
        tmp |= (words[2] >> 14) & BITMASK(18);
1507
0
        tmp = UINT2INT(tmp, 32);
1508
0
        subp->orbit.i0 = tmp * pow(2.0, -31);
1509
1510
0
        tmp = (words[2] & BITMASK(14)) << 18;                 // omega
1511
0
        tmp |= (words[3] >> 14) & BITMASK(18);
1512
0
        tmp = UINT2INT(tmp, 32);
1513
0
        subp->orbit.omega = tmp * pow(2.0, -31);
1514
1515
0
        tmp = (words[4] >> 16) & BITMASK(14);                 // idot
1516
0
        tmp = UINT2INT(tmp, 14);
1517
0
        subp->orbit.IDOT = tmp * pow(2.0, -43);
1518
1519
0
        subp->is_almanac = SUBFRAME_ORBIT;
1520
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1521
0
        mask = SUBFRAME_SET;
1522
0
        break;
1523
0
    case 3:
1524
0
        word_desc = "Ephemeris 3";
1525
0
        subp->orbit.sv = tSVID;
1526
0
        subp->orbit.IODE = (words[0] >> 14) & BITMASK(10);    // IODnav
1527
1528
0
        tmp = (words[0] & BITMASK(14)) << 10;                 // Omegad
1529
0
        tmp |= (words[1] >> 22) & BITMASK(10);
1530
0
        tmp = UINT2INT(tmp, 24);
1531
0
        subp->orbit.Omegad = tmp * pow(2.0, -43);
1532
1533
0
        tmp = (words[1] >> 6) & BITMASK(16);                  // deltan
1534
0
        tmp = UINT2INT(tmp, 16);
1535
0
        subp->orbit.deltan = tmp * pow(2.0, -43);
1536
1537
0
        tmp = (words[1] & BITMASK(6)) << 10;                  // Cuc
1538
0
        tmp |= (words[2] >> 22) & BITMASK(10);
1539
0
        tmp = UINT2INT(tmp, 16);
1540
0
        subp->orbit.Cuc = tmp * pow(2.0, -29);
1541
1542
0
        tmp = (words[2] >> 6) & BITMASK(16);                  // Cus
1543
0
        tmp = UINT2INT(tmp, 16);
1544
0
        subp->orbit.Cus = tmp * pow(2.0, -29);
1545
1546
0
        tmp = (words[2] & BITMASK(6)) << 10;                  // Crc
1547
0
        tmp |= (words[3] >> 22) & BITMASK(10);
1548
0
        tmp = UINT2INT(tmp, 16);
1549
0
        subp->orbit.Crc = tmp * pow(2.0, -5);
1550
1551
0
        tmp = ((words[3] >> 14) & BITMASK(8)) << 8;           // Crs
1552
0
        tmp |= (words[4] >> 22) & BITMASK(8);
1553
0
        tmp = UINT2INT(tmp, 16);
1554
0
        subp->orbit.Crs = tmp * pow(2.0, -5);
1555
1556
0
        subp->orbit.SISAb = (words[4] >> 14) & BITMASK(8);    // SISA(E1,E5b)
1557
1558
0
        subp->is_almanac = SUBFRAME_ORBIT;
1559
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1560
0
        mask = SUBFRAME_SET;
1561
0
        break;
1562
0
    case 4:
1563
0
        word_desc = "Ephemeris 4";
1564
0
        mask = SUBFRAME_SET;
1565
0
        subp->orbit.sv = tSVID;
1566
0
        subp->orbit.IODE = (words[0] >> 14) & BITMASK(10);    // IODnav
1567
0
        tmp = (words[0] >> 8) & BITMASK(6);                   // SVID
1568
0
        if (tSVID != (unsigned)tmp) {
1569
            // WTF?
1570
0
            mask = 0;
1571
0
        }
1572
0
        tmp = (words[0] & BITMASK(8)) << 8;                   // Cic
1573
0
        tmp |= (words[1] >> 24) & BITMASK(8);
1574
0
        tmp = UINT2INT(tmp, 16);
1575
0
        subp->orbit.Cic = tmp * pow(2.0, -29);
1576
1577
0
        tmp = (words[1] >> 8) & BITMASK(16);                  // Cis
1578
0
        tmp = UINT2INT(tmp, 16);
1579
0
        subp->orbit.Cis = tmp * pow(2.0, -29);
1580
1581
0
        tmp = (words[1] & BITMASK(8)) << 6;                   // toc
1582
0
        tmp |= (words[2] >> 26) & BITMASK(6);
1583
0
        subp->orbit.toc = tmp * 60;
1584
1585
0
        tmp = (words[2] & BITMASK(26)) << 5;                  // af0
1586
0
        tmp |= (words[3] >> 27) & BITMASK(5);
1587
0
        tmp = UINT2INT(tmp, 31);
1588
0
        subp->orbit.af0 = tmp * pow(2.0, -34);
1589
1590
0
        tmp = ((words[3] >> 14) & BITMASK(13)) << 8;          // af1
1591
0
        tmp |= (words[4] >> 22) & BITMASK(8);
1592
0
        tmp = UINT2INT(tmp, 21);
1593
0
        subp->orbit.af1 = tmp * pow(2.0, -46);
1594
1595
0
        tmp = (words[4] >> 16) & BITMASK(6);                  // af2
1596
0
        tmp = UINT2INT(tmp, 6);
1597
0
        subp->orbit.af2 = tmp * pow(2.0, -59);
1598
1599
0
        subp->is_almanac = SUBFRAME_ORBIT;
1600
0
        subp->orbit.type = ORBIT_EPHEMERIS;
1601
0
        break;
1602
0
    case 5:
1603
0
        word_desc = "Ionosphere";
1604
0
        subp->WN = (words[2] >> 11) & BITMASK(12);            // WN
1605
0
        subp->TOW17 = (words[2] & BITMASK(11)) << 9;          // TOW
1606
0
        subp->TOW17 |= (words[3] >> 23) & BITMASK(9);
1607
0
        mask = SUBFRAME_SET;
1608
0
        break;
1609
0
    case 6:
1610
0
        word_desc = "GST-UTC";
1611
0
        subp->TOW17 = ((words[3] >> 14) & BITMASK(7)) << 13;  // TOW
1612
0
        subp->TOW17 |= (words[4] >> 17) & BITMASK(13);
1613
0
        mask = SUBFRAME_SET;
1614
0
        break;
1615
0
    case 7:
1616
0
        word_desc = "Almanacs 1";
1617
0
        mask = SUBFRAME_SET;
1618
0
        subp->is_almanac = SUBFRAME_ORBIT;
1619
0
        subp->orbit.type = ORBIT_ALMANAC;
1620
0
        subp->orbit.IODA = (words[0] >> 20) & BITMASK(4);     // IODa
1621
0
        subp->orbit.WN = (words[0] >> 18) & BITMASK(2);       // WNa
1622
0
        subp->orbit.toa = ((words[0] >> 8) & BITMASK(10)) * 600;   // toa
1623
0
        subp->orbit.sv = (words[0] >> 2) & BITMASK(6);        // SVN1
1624
0
        if (0 == subp->orbit.sv || 36 < subp->orbit.sv) {
1625
            // dummy, or reserved, almanac
1626
0
            mask = 0;
1627
0
            break;
1628
0
        }
1629
0
        tmp = (words[0] & BITMASK(2)) << 11;                  // delta sqrtA
1630
0
        tmp |= (words[1] >> 21) & BITMASK(11);
1631
0
        tmp = UINT2INT(tmp, 13);
1632
        // Table 1 from ICD
1633
0
        subp->orbit.sqrtA = (tmp * pow(2.0, -9)) + sqrt(29600000);
1634
0
        if (2600 > subp->orbit.sqrtA) {
1635
            // Sanity check: A must be greater than Earth radius
1636
0
            mask = 0;
1637
0
        }
1638
1639
0
        tmp = (words[1] >> 10) & BITMASK(11);                 // e
1640
0
        subp->orbit.eccentricity = tmp * pow(2.0, -16);
1641
1642
0
        tmp = (words[1] & BITMASK(10)) << 6;                  // omega
1643
0
        tmp |= (words[2] >> 26) & BITMASK(6);
1644
0
        tmp = UINT2INT(tmp, 16);
1645
0
        subp->orbit.omega = tmp * pow(2.0, -15);
1646
1647
0
        tmp = (words[2] >> 15) & BITMASK(11);                 // deltai
1648
0
        tmp = UINT2INT(tmp, 11);
1649
        // Table 1 from ICD
1650
0
        subp->orbit.i0 = (tmp * pow(2.0, -14)) + (56.0 / 180.0);
1651
1652
0
        tmp = (words[2] & BITMASK(15)) << 1;                  // Omega0
1653
0
        tmp |= (words[3] >> 31) & 1;
1654
0
        tmp = UINT2INT(tmp, 16);
1655
0
        subp->orbit.Omega0 = tmp * pow(2.0, -15);
1656
1657
0
        tmp = (words[3] >> 20) & BITMASK(11);                 // Omegadot
1658
0
        tmp = UINT2INT(tmp, 11);
1659
0
        subp->orbit.Omegad = tmp * pow(2.0, -33);
1660
1661
0
        tmp = ((words[3] >> 14) & BITMASK(6)) << 10;          // M0
1662
0
        tmp |= (words[4] >> 20) & BITMASK(10);
1663
0
        tmp = UINT2INT(tmp, 16);
1664
0
        subp->orbit.M0 = tmp * pow(2.0, -15);
1665
1666
0
        break;
1667
0
    case 8:
1668
        // Now it gets weird.  2/2 of Almanac 1, and 1/2 of Almanac 2
1669
0
        word_desc = "Almanacs 2";
1670
0
        subp->orbit1.sv = (words[1] >> 13) & BITMASK(6);      // SVID2
1671
0
        if (0 == subp->orbit1.sv ||
1672
0
            36 < subp->orbit1.sv) {
1673
            // dummy, or reserved, almanac
1674
0
            mask = 0;
1675
0
            break;
1676
0
        }
1677
0
        mask = SUBFRAME_SET;
1678
0
        subp->is_almanac = SUBFRAME_ORBIT;
1679
0
        subp->orbit.type = ORBIT_ALMANAC;
1680
1681
        // how do we know the SVID1?  It is one less.
1682
0
        subp->orbit.sv = subp->orbit1.sv - 1;
1683
1684
0
        subp->orbit.IODA = (words[0] >> 20) & BITMASK(4);     // IODa
1685
1686
0
        tmp = (words[0] >> 4) & BITMASK(16);                  // af0
1687
0
        tmp = UINT2INT(tmp, 16);
1688
0
        subp->orbit.af0 = tmp * pow(2.0, -19);
1689
1690
0
        tmp = (words[0] & BITMASK(4)) << 9;                   // af1
1691
0
        tmp |= (words[1] >> 23) & BITMASK(9);
1692
0
        tmp = UINT2INT(tmp, 13);
1693
0
        subp->orbit.af1 = tmp * pow(2.0, -38);
1694
1695
0
        subp->orbit.E5bHS = (words[1] >> 21) & BITMASK(2);    // E5bHS
1696
0
        subp->orbit.E1BHS = (words[1] >> 19) & BITMASK(2);    // E1BHS
1697
1698
        // start of 2nd SV
1699
0
        subp->orbit1.type = ORBIT_ALMANAC;
1700
0
        subp->orbit1.IODA = subp->orbit.IODA;                 // IODa
1701
0
        tmp = words[1] & BITMASK(13);                         // delta sqrtA
1702
0
        tmp = UINT2INT(tmp, 13);
1703
        // Table 1 from ICD
1704
0
        subp->orbit1.sqrtA = (tmp * pow(2.0, -9)) + sqrt(29600000);
1705
0
        if (2600 > subp->orbit.sqrtA) {
1706
            // Sanity check: A must be greater than Earth radius
1707
0
            mask = 0;
1708
0
        }
1709
1710
0
        tmp = (words[2] >> 21) & BITMASK(11);                 // e
1711
0
        subp->orbit1.eccentricity = tmp * pow(2.0, -16);
1712
1713
0
        tmp = (words[2] >> 5) & BITMASK(16);                  // omega
1714
0
        tmp = UINT2INT(tmp, 16);
1715
0
        subp->orbit1.omega = tmp * pow(2.0, -15);
1716
1717
0
        tmp = (words[2] & BITMASK(5)) << 6;                   // deltai
1718
0
        tmp |= (words[3] >> 26) & BITMASK(6);
1719
0
        tmp = UINT2INT(tmp, 11);
1720
        // Table 1 from ICD
1721
0
        subp->orbit1.i0 = (tmp * pow(2.0, -14)) + (56.0 / 180.0);
1722
1723
0
        tmp = ((words[3] >> 14) & BITMASK(12)) << 4;          // Omega0
1724
0
        tmp |= (words[4] >> 26) & BITMASK(4);
1725
0
        tmp = UINT2INT(tmp, 16);
1726
0
        subp->orbit1.Omega0 = tmp * pow(2.0, -15);
1727
1728
0
        tmp = (words[4] >> 15) & BITMASK(11);                 // Omegadot
1729
0
        tmp = UINT2INT(tmp, 11);
1730
0
        subp->orbit1.Omegad = tmp * pow(2.0, -33);
1731
1732
0
        break;
1733
0
    case 9:
1734
0
        word_desc = "Almanacs 3";
1735
0
        subp->orbit1.sv = (words[2] >> 17) & BITMASK(6);      // SVID3
1736
0
        if (0 >= subp->orbit1.sv || 36 < subp->orbit1.sv) {
1737
            // dummy, or reserved, almanac
1738
0
            mask = 0;
1739
0
            break;
1740
0
        }
1741
        // save for use in word 10
1742
0
        session->last_svid3_gal = subp->orbit1.sv;
1743
0
        mask = SUBFRAME_SET;
1744
0
        subp->is_almanac = SUBFRAME_ORBIT;
1745
0
        subp->orbit.type = ORBIT_ALMANAC;
1746
1747
        // how do we know the SVID2?  It is one less.
1748
0
        subp->orbit.sv = subp->orbit1.sv - 1;
1749
0
        subp->orbit.IODA = (words[0] >> 20) & BITMASK(4);     // IODa
1750
0
        subp->orbit.WN = (words[0] >> 18) & BITMASK(2);       // WNa
1751
0
        subp->orbit.toa = ((words[0] >> 8) & BITMASK(10)) * 600;   // toa
1752
1753
0
        tmp = (words[0] & BITMASK(8)) << 8;     // M0
1754
0
        tmp |= (words[1] >> 24) & BITMASK(8);
1755
0
        tmp = UINT2INT(tmp, 16);
1756
0
        subp->orbit.M0 = tmp * pow(2.0, -15);
1757
1758
0
        tmp = (words[1] >> 8) & BITMASK(16);                  // af0
1759
0
        tmp = UINT2INT(tmp, 16);
1760
0
        subp->orbit.af0 = tmp * pow(2.0, -19);
1761
1762
0
        tmp = (words[1] & BITMASK(8)) << 5;                   // af1
1763
0
        tmp |= (words[2] >> 27) & BITMASK(5);
1764
0
        tmp = UINT2INT(tmp, 13);
1765
0
        subp->orbit.af1 = tmp * pow(2.0, -38);
1766
1767
0
        subp->orbit.E5bHS = (words[2] >> 25) & BITMASK(2);    // E5bHS
1768
0
        subp->orbit.E1BHS = (words[2] >> 23) & BITMASK(2);    // E1BHS
1769
1770
        // SVID3
1771
0
        subp->orbit1.type = ORBIT_ALMANAC;
1772
0
        subp->orbit1.IODA = subp->orbit.IODA;                 // IODa
1773
0
        tmp = (words[2] >> 4) & BITMASK(13);                  // delta sqrtA?
1774
0
        tmp = UINT2INT(tmp, 13);
1775
        // Table 1 from ICD
1776
0
        subp->orbit1.sqrtA = (tmp * pow(2.0, -9)) + sqrt(29600000);
1777
0
        if (2600 > subp->orbit.sqrtA) {
1778
            // Sanity check: A must be greater than Earth radius
1779
0
            mask = 0;
1780
0
        }
1781
1782
0
        tmp = (words[2] & BITMASK(4)) << 7;                   // e
1783
0
        tmp |= (words[3] >> 11) & BITMASK(7);
1784
0
        subp->orbit1.eccentricity = tmp * pow(2.0, -16);
1785
1786
0
        tmp = ((words[3] >> 14) & BITMASK(11)) << 5;          // omega
1787
0
        tmp |= (words[4] >> 25) & BITMASK(5);
1788
0
        tmp = UINT2INT(tmp, 16);
1789
0
        subp->orbit1.omega = tmp * pow(2.0, -15);
1790
1791
0
        tmp = (words[4] >> 14) & BITMASK(11);                 // i0
1792
0
        tmp = UINT2INT(tmp, 11);
1793
        // Table 1 from ICD
1794
0
        subp->orbit1.i0 = (tmp * pow(2.0, -14)) + (56.0 / 180.0);
1795
1796
0
        break;
1797
0
    case 10:
1798
0
        word_desc = "Almanacs 4";
1799
0
        subp->is_almanac = SUBFRAME_ORBIT;
1800
0
        subp->orbit.type = ORBIT_ALMANAC;
1801
0
        mask = SUBFRAME_SET;
1802
1803
        // how do we know the SVID3?
1804
0
        if (9 == session->last_word_gal ||
1805
0
            10 == session->last_word_gal) {
1806
0
            subp->orbit.sv = session->last_svid3_gal;
1807
0
        }
1808
0
        subp->orbit.IODA = (words[0] >> 20) & BITMASK(4);     // IODa
1809
0
        tmp = (words[0] >> 4) & BITMASK(16);                  // Omega0
1810
0
        tmp = UINT2INT(tmp, 16);
1811
0
        subp->orbit.Omega0 = tmp * pow(2.0, -15);
1812
1813
0
        tmp = (words[0] & BITMASK(4)) << 7;                   // Omegadot
1814
0
        tmp |= (words[1] >> 25) & BITMASK(7);
1815
0
        tmp = UINT2INT(tmp, 11);
1816
0
        subp->orbit.Omegad = tmp * pow(2.0, -33);
1817
1818
0
        tmp = (words[1] >> 9) & BITMASK(16);                  // M0
1819
0
        tmp = UINT2INT(tmp, 16);
1820
0
        subp->orbit.M0 = tmp * pow(2.0, -15);
1821
1822
0
        tmp = (words[1] & BITMASK(9)) << 7;                   // af0
1823
0
        tmp |= (words[2] >> 25) & BITMASK(7);
1824
0
        tmp = UINT2INT(tmp, 16);
1825
0
        subp->orbit.af0 = tmp * pow(2.0, -19);
1826
1827
0
        tmp = (words[2] >> 12) & BITMASK(13);                 // af1
1828
0
        tmp = UINT2INT(tmp, 13);
1829
0
        subp->orbit.af1 = tmp * pow(2.0, -38);
1830
1831
0
        subp->orbit.E5bHS = (words[2] >> 10) & BITMASK(2);    // E5bHS
1832
0
        subp->orbit.E1BHS = (words[2] >> 8) & BITMASK(2);     // E1BHS
1833
1834
        // time
1835
        // tmp = (words[2] & BITMASK(8)) << 8;                   // A0G
1836
        // tmp |= (words[3] >> 25) & BITMASK(8);
1837
        // tmp = UINT2INT(tmp, 16);
1838
        // subp->orbit.af0 = tmp * pow(2.0, -19);
1839
1840
        // tmp = ((words[3] >> 14) & BITMASK(10)) << 2;          // A1G
1841
        // tmp |= (words[4] >> 28) & BITMASK(2);
1842
        // tmp = UINT2INT(tmp, 16);
1843
        // subp->orbit.af0 = tmp * pow(2.0, -19);
1844
1845
        // subp->orbit.tog = (words[4] >> 20) & BITMASK(8);   // t0g
1846
        // subp->orbit.WN = (words[4] >> 14) & BITMASK(6);    // WN0g
1847
1848
1849
0
        break;
1850
0
    case 16:
1851
0
        word_desc = "Reduced Clock and Ephemeris Data";
1852
0
        break;
1853
0
    case 17:
1854
0
        word_desc = "FEC2 Reed-Solomon for Clock and Ephemeris Data";
1855
0
        break;
1856
0
    case 63:
1857
0
        word_desc = "Dummy Page";
1858
0
        break;
1859
0
    default:
1860
0
        word_desc = "Unknown Word";
1861
0
        break;
1862
0
    }
1863
    // save word_type for SVID3 detection
1864
0
    session->last_word_gal = word_type;
1865
1866
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1867
0
             "SUB,GAL: len %u even %u page_type %u word_type %u (%s)\n",
1868
0
             numwords, even, page_type, word_type, word_desc);
1869
1870
0
    return mask;
1871
0
}
1872
1873
1874
/* Stub of code to decode GLONASS Subframes
1875
 *
1876
 * ZED-F9P_IntegrationManual_(UBX-18010802).pdf
1877
 * Section 3.13.1.3 GLONASS
1878
 * L10F and L20F only
1879
 * ICD_GLONASS_5.1_(2008)_en.pdf "ICD L1, L2 GLONASS"
1880
 * gotta decode the u-blox munging and the GLONASS packing...
1881
 *
1882
 * 4 words
1883
 */
1884
static gps_mask_t subframe_glo(struct gps_device_t *session,
1885
                               unsigned int tSVID,
1886
                               uint32_t words[],
1887
                               unsigned int numwords)
1888
0
{
1889
0
    char *word_desc = "";
1890
0
    struct subframe_t *subp;
1891
0
    unsigned stringnum = (words[0] >> 27) & BITMASK(4);
1892
0
    unsigned supernum = (words[3] >> 16) & BITMASK(4);
1893
0
    unsigned framenum = words[3] & BITMASK(4);
1894
1895
0
    subp = &session->gpsdata.subframe;
1896
0
    init_subframe(subp, GNSSID_GLO, (uint8_t)tSVID);
1897
1898
0
    GPSD_LOG(LOG_DATA, &session->context->errout,
1899
0
             "SUB,GLO: tSVID %u len %u: "
1900
0
             "%08x %08x %08x %08x\n", tSVID, numwords,
1901
0
             words[0], words[1], words[2], words[3]);
1902
1903
0
    switch (stringnum) {
1904
0
    case 1:
1905
0
        word_desc = "Ephemeris 1";
1906
0
        break;
1907
0
    case 2:
1908
0
        word_desc = "Ephemeris 2";
1909
0
        break;
1910
0
    case 3:
1911
0
        word_desc = "Ephemeris 3";
1912
0
        break;
1913
0
    case 4:
1914
0
        word_desc = "Ephemeris 4";
1915
0
        break;
1916
0
    case 5:
1917
0
        word_desc = "Time";
1918
0
        break;
1919
0
    case 6:
1920
0
        FALLTHROUGH
1921
0
    case 8:
1922
0
        FALLTHROUGH
1923
0
    case 10:
1924
0
        FALLTHROUGH
1925
0
    case 12:
1926
0
        FALLTHROUGH
1927
0
    case 14:
1928
0
        if (5 == framenum) {
1929
0
            word_desc = "Extra 1";
1930
0
        } else {
1931
0
            word_desc = "Almanac 1";
1932
0
        }
1933
0
        break;
1934
0
    case 7:
1935
0
        FALLTHROUGH
1936
0
    case 9:
1937
0
        FALLTHROUGH
1938
0
    case 11:
1939
0
        FALLTHROUGH
1940
0
    case 13:
1941
0
        FALLTHROUGH
1942
0
    case 15:
1943
0
        if (5 == framenum) {
1944
0
            word_desc = "Extra 2";
1945
0
        } else {
1946
0
            word_desc = "Almanac 2";
1947
0
        }
1948
0
        break;
1949
0
    default:
1950
0
        word_desc = "Unknown stringnum";
1951
0
        break;
1952
0
    }
1953
0
    GPSD_LOG(LOG_PROG, &session->context->errout,
1954
0
             "SUB,GLO: len %u supernum %u framenum %u stringnum %u (%s)\n",
1955
0
             numwords, supernum, framenum, stringnum, word_desc);
1956
0
    return 0;
1957
0
}
1958
1959
1960
gps_mask_t gpsd_interpret_subframe_raw(struct gps_device_t *session,
1961
                                       gnssid_t gnssId,
1962
                                       unsigned int sigId,
1963
                                       unsigned int tSVID,
1964
                                       uint32_t words[],
1965
                                       unsigned int numwords)
1966
0
{
1967
0
    unsigned int i;
1968
0
    uint8_t preamble;
1969
0
    unsigned int numwords_expected = 0;
1970
1971
0
    if (0 == session->subframe_count++ &&
1972
0
        0 < gpsd_serial_isatty(session)) {
1973
0
        speed_t speed = gpsd_get_speed(session);
1974
1975
0
        if (speed < 38400) {
1976
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
1977
0
                     "SUB: speed less than 38,400 may cause data lag and "
1978
0
                     "loss of functionality\n");
1979
0
        }
1980
0
    }
1981
1982
0
    switch (gnssId) {
1983
0
    case GNSSID_GPS:
1984
0
        FALLTHROUGH
1985
0
    case GNSSID_QZSS:
1986
        // GPS and QZSS use the same subframe structure
1987
0
        numwords_expected = 10;
1988
0
        break;
1989
0
    case GNSSID_SBAS:
1990
0
        GPSD_LOG(LOG_INFO, &session->context->errout,
1991
0
                 "SUB,SBAS: subframe protocol is not publicly documented");
1992
0
        return 0;
1993
0
    case GNSSID_GAL:
1994
0
        numwords_expected = 8;
1995
0
        if (numwords_expected == numwords) {
1996
0
            return subframe_gal(session, tSVID, words, numwords);
1997
0
        }
1998
0
        break;
1999
2000
0
    case GNSSID_BD:
2001
0
        switch (sigId) {
2002
0
        case 0:
2003
0
            numwords_expected = 10;
2004
0
            break;
2005
0
        case 6:
2006
            // BDS B1 Cd, 3, 9 or  19, test later
2007
0
            numwords_expected = numwords;
2008
0
            break;
2009
0
        case 8:
2010
            // BDS B2 ad
2011
0
            numwords_expected = 9;
2012
0
            break;
2013
0
        default:
2014
0
            GPSD_LOG(LOG_WARN, &session->context->errout,
2015
0
                     "SUB: BDS, unknown sigId %u\n", sigId);
2016
0
            numwords_expected = 99;
2017
0
            break;
2018
0
        }
2019
0
        if (numwords_expected == numwords) {
2020
0
            return subframe_bds(session, sigId, tSVID, words, numwords);
2021
0
        }
2022
0
        break;
2023
0
    case GNSSID_GLO:
2024
0
        numwords_expected = 4;
2025
0
        if (numwords_expected == numwords) {
2026
0
            return subframe_glo(session, tSVID, words, numwords);
2027
0
        }
2028
0
        break;
2029
0
    case GNSSID_CNT:
2030
0
        FALLTHROUGH
2031
0
    case GNSSID_IMES:
2032
0
        FALLTHROUGH
2033
0
    case GNSSID_IRNSS:
2034
0
        FALLTHROUGH
2035
0
    default:
2036
0
        GPSD_LOG(LOG_INFO, &session->context->errout,
2037
0
                 "SUB: Unsupportd gnssId %u\n", gnssId);
2038
0
        return 0;
2039
0
    }
2040
2041
0
    if (numwords_expected > numwords) {
2042
0
        GPSD_LOG(LOG_WARN, &session->context->errout,
2043
0
                 "SUB: gnssId %u  Expected numwords %u, got %u\n",
2044
0
                 gnssId, numwords_expected, numwords);
2045
0
        return 0;
2046
0
    }
2047
2048
    /*
2049
     * This function assumes an array of 10 ints, each of which carries
2050
     * a raw 30-bit GPS word use your favorite search engine to find the
2051
     * latest version of the specification: IS-GPS-200.
2052
     *
2053
     * Each raw 30-bit word is made of 24 data bits and 6 parity bits. The
2054
     * raw word and transport word are emitted from the GPS MSB-first and
2055
     * right justified. In other words, masking the raw word against 0x3f
2056
     * will return just the parity bits. Masking with 0x3fffffff and shifting
2057
     * 6 bits to the right returns just the 24 data bits. The top two bits
2058
     * (b31 and b30) are undefined; chipset designers may store copies of
2059
     * the bits D29* and D30* here to aid parity checking.
2060
     *
2061
     * Since bits D29* and D30* are not available in word 0, it is tested for
2062
     * a known preamble to help check its validity and determine whether the
2063
     * word is inverted.
2064
     *
2065
     */
2066
0
    GPSD_LOG(LOG_DATA, &session->context->errout,
2067
0
             "SUB,GPS: gpsd_interpret_subframe_raw: "
2068
0
             "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
2069
0
             words[0], words[1], words[2], words[3], words[4],
2070
0
             words[5], words[6], words[7], words[8], words[9]);
2071
2072
0
    preamble = (uint8_t)((words[0] >> 22) & BITMASK(8));
2073
0
    if (preamble == 0x8b) {       // preamble is inverted
2074
0
        words[0] ^= 0x3fffffc0;   // invert
2075
0
    } else if (preamble != 0x74) {
2076
        // strangely this is very common, so don't log it
2077
0
        GPSD_LOG(LOG_DATA, &session->context->errout,
2078
0
                 "SUB,GPS: gpsd_interpret_subframe_raw: bad preamble 0x%x\n",
2079
0
                 preamble);
2080
0
        return 0;
2081
0
    }
2082
0
    words[0] = (words[0] >> 6) & BITMASK(24);
2083
2084
0
    for (i = 1; i < 10; i++) {
2085
0
        int invert;
2086
0
        uint32_t parity;
2087
        // D30* says invert
2088
0
        invert = (words[i] & 0x40000000) ? 1 : 0;
2089
        // inverted data, invert it back
2090
0
        if (invert) {
2091
0
            words[i] ^= 0x3fffffc0;
2092
0
        }
2093
0
        parity = (uint32_t)isgps_parity((isgps30bits_t)words[i]);
2094
0
        if (parity != (words[i] & BITMASK(6))) {
2095
0
            GPSD_LOG(LOG_DATA, &session->context->errout,
2096
0
                     "SUB,GPS: gpsd_interpret_subframe_raw parity fail "
2097
0
                     "words[%d] 0x%x != 0x%x\n",
2098
0
                     i, parity, (words[i] & 1));
2099
0
            return 0;
2100
0
        }
2101
0
        words[i] = (words[i] >> 6) & BITMASK(24);
2102
0
    }
2103
2104
0
    return gpsd_interpret_subframe(session, gnssId, tSVID, words);
2105
0
}
2106
2107
// vim: set expandtab shiftwidth=4