cleanup specfile for packaging
[profile/ivi/gpsd.git] / subframe.c
1 /* subframe.c -- interpret satellite subframe data.
2  *
3  * This file is Copyright (c) 2010 by the GPSD project
4  * BSD terms apply: see the file COPYING in the distribution root for details.
5  */
6 #include <sys/types.h>
7
8 #include "gpsd.h"
9 #include "timebase.h"
10
11 #ifdef __NOT_YET__
12 static char sf4map[] =
13     { -1, 57, 25, 26, 27, 28, 57, 29, 30, 31, 32, 57, 62, 52, 53, 54, 57, 55,
14     56, 58, 59, 57, 60, 61, 62, 63
15 };
16
17 static char sf5map[] =
18     { -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
19     20, 21, 22, 23, 24, 51
20 };
21 #endif
22
23 /*@ -usedef @*/
24 int gpsd_interpret_subframe_raw(struct gps_device_t *session,
25                                 unsigned int words[])
26 {
27     unsigned int i;
28     unsigned int preamble, parity;
29
30     /*
31      * This function assumes an array of 10 ints, each of which carries
32      * a raw 30-bit GPS word use your favorite search engine to find the
33      * latest version of the specification: IS-GPS-200.
34      *
35      * Each raw 30-bit word is made of 24 data bits and 6 parity bits. The
36      * raw word and transport word are emitted from the GPS MSB-first and
37      * right justified. In other words, masking the raw word against 0x3f
38      * will return just the parity bits. Masking with 0x3fffffff and shifting
39      * 6 bits to the right returns just the 24 data bits. The top two bits
40      * (b31 and b30) are undefined; chipset designers may store copies of
41      * the bits D29* and D30* here to aid parity checking.
42      *
43      * Since bits D29* and D30* are not available in word 0, it is tested for
44      * a known preamble to help check its validity and determine whether the
45      * word is inverted.
46      *
47      */
48     gpsd_report(LOG_IO, "50B: gpsd_interpret_subframe_raw: "
49                 "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
50                 words[0], words[1], words[2], words[3], words[4],
51                 words[5], words[6], words[7], words[8], words[9]);
52
53     preamble = (words[0] >> 22) & 0xff;
54     if (preamble == 0x8b) {     /* preamble is inverted */
55         words[0] ^= 0x3fffffc0; /* invert */
56     } else if (preamble != 0x74) {
57         gpsd_report(LOG_WARN,
58                     "50B: gpsd_interpret_subframe_raw: bad preamble 0x%x\n",
59                     preamble);
60         return 0;
61     }
62     words[0] = (words[0] >> 6) & 0xffffff;
63
64     for (i = 1; i < 10; i++) {
65         int invert;
66         /* D30* says invert */
67         invert = (words[i] & 0x40000000) ? 1 : 0;
68         /* inverted data, invert it back */
69         if (invert) {
70             words[i] ^= 0x3fffffc0;
71         }
72         parity = isgps_parity(words[i]);
73         if (parity != (words[i] & 0x3f)) {
74             gpsd_report(LOG_PROG,
75                         "50B: gpsd_interpret_subframe_raw parity fail words[%d] 0x%x != 0x%x\n",
76                         i, parity, (words[i] & 0x1));
77             return 0;
78         }
79         words[i] = (words[i] >> 6) & 0xffffff;
80     }
81
82     gpsd_interpret_subframe(session, words);
83     return 0;
84 }
85
86 void gpsd_interpret_subframe(struct gps_device_t *session,
87                              unsigned int words[])
88 {
89     /*
90      * Heavy black magic begins here!
91      *
92      * A description of how to decode these bits is at
93      * <http://home-2.worldonline.nl/~samsvl/nav2eu.htm>
94      *
95      * We're mostly looking for subframe 4 page 18 word 9, the leap second
96      * correction. This functions assumes an array of words without parity
97      * or inversion (inverted word 0 is OK). It may be called directly by a
98      * driver if the chipset emits acceptable data.
99      *
100      * To date this code has been tested on iTrax, SiRF and ublox.
101      */
102     unsigned int pageid, subframe, data_id, leap, lsf, wnlsf, dn, preamble;
103     gpsd_report(LOG_IO,
104                 "50B: gpsd_interpret_subframe: "
105                 "%06x %06x %06x %06x %06x %06x %06x %06x %06x %06x\n",
106                 words[0], words[1], words[2], words[3], words[4],
107                 words[5], words[6], words[7], words[8], words[9]);
108
109     preamble = (unsigned int)((words[0] >> 16) & 0xffL);
110     if (preamble == 0x8b) {
111         preamble ^= 0xff;
112         words[0] ^= 0xffffff;
113     }
114     if (preamble != 0x74) {
115         gpsd_report(LOG_WARN,
116                     "50B: gpsd_interpret_subframe bad preamble: 0x%x header 0x%x\n",
117                     preamble, words[0]);
118         return;
119     }
120     /* The subframe ID is in the Hand Over Word (page 80) */
121     subframe = ((words[1] >> 2) & 0x07);
122     /*
123      * Consult the latest revision of IS-GPS-200 for the mapping
124      * between magic SVIDs and pages.
125      */
126     pageid = (words[2] & 0x3F0000) >> 16;
127     data_id = (words[2] >> 22) & 0x3;
128     gpsd_report(LOG_PROG,
129                 "50B: gpsd_interpret_subframe: Subframe %d SVID %d data_id %d\n",
130                 subframe, pageid, data_id);
131     switch (subframe) {
132     case 1:
133         /* get Week Number WN) from subframe 1 */
134         session->context->gps_week =
135             (unsigned short)((words[2] & 0xffc000) >> 14);
136         gpsd_report(LOG_PROG, "50B: WN: %u\n", session->context->gps_week);
137         break;
138     case 4:
139         switch (pageid) {
140         case 55:
141             /*
142              * "The requisite 176 bits shall occupy bits 9 through 24 of word
143              * TWO, the 24 MSBs of words THREE through EIGHT, plus the 16 MSBs
144              * of word NINE." (word numbers changed to account for zero-indexing)
145              *
146              * Since we've already stripped the low six parity bits, and shifted
147              * the data to a byte boundary, we can just copy it out. */
148         {
149             char str[24];
150             int j = 0;
151             /*@ -type @*/
152             str[j++] = (words[2] >> 8) & 0xff;
153             str[j++] = (words[2]) & 0xff;
154
155             str[j++] = (words[3] >> 16) & 0xff;
156             str[j++] = (words[3] >> 8) & 0xff;
157             str[j++] = (words[3]) & 0xff;
158
159             str[j++] = (words[4] >> 16) & 0xff;
160             str[j++] = (words[4] >> 8) & 0xff;
161             str[j++] = (words[4]) & 0xff;
162
163             str[j++] = (words[5] >> 16) & 0xff;
164             str[j++] = (words[5] >> 8) & 0xff;
165             str[j++] = (words[5]) & 0xff;
166
167             str[j++] = (words[6] >> 16) & 0xff;
168             str[j++] = (words[6] >> 8) & 0xff;
169             str[j++] = (words[6]) & 0xff;
170
171             str[j++] = (words[7] >> 16) & 0xff;
172             str[j++] = (words[7] >> 8) & 0xff;
173             str[j++] = (words[7]) & 0xff;
174
175             str[j++] = (words[8] >> 16) & 0xff;
176             str[j++] = (words[8] >> 8) & 0xff;
177             str[j++] = (words[8]) & 0xff;
178
179             str[j++] = (words[9] >> 16) & 0xff;
180             str[j++] = (words[9] >> 8) & 0xff;
181             str[j++] = '\0';
182             /*@ +type @*/
183             gpsd_report(LOG_INF, "50B: gps system message is %s\n", str);
184         }
185             break;
186         case 56:
187             leap = (words[8] & 0xff0000) >> 16; /* current leap seconds */
188             /* careful WN is 10 bits, but WNlsf is 8 bits! */
189             wnlsf = (words[8] & 0x00ff00) >> 8; /* WNlsf (Week Number of LSF) */
190             dn = (words[8] & 0x0000FF); /* DN (Day Number of LSF) */
191             lsf = (words[9] & 0xff0000) >> 16;  /* leap second future */
192             /*
193              * On SiRFs, the 50BPS data is passed on even when the
194              * parity fails.  This happens frequently.  So the driver 
195              * must be extra careful that bad data does not reach here.
196              */
197             if (LEAP_SECONDS > leap) {
198                 /* something wrong */
199                 gpsd_report(LOG_ERROR, "50B: Invalid leap_seconds: %d\n",
200                             leap);
201                 leap = LEAP_SECONDS;
202                 session->context->valid &= ~LEAP_SECOND_VALID;
203             } else {
204                 gpsd_report(LOG_INF,
205                             "50B: leap-seconds: %d, lsf: %d, WNlsf: %d, DN: %d \n",
206                             leap, lsf, wnlsf, dn);
207                 session->context->valid |= LEAP_SECOND_VALID;
208                 if (leap != lsf) {
209                     gpsd_report(LOG_PROG, "50B: leap-second change coming\n");
210                 }
211             }
212             session->context->leap_seconds = (int)leap;
213             break;
214         default:
215             ;                   /* no op */
216         }
217         break;
218     }
219     return;
220 }
221
222 /*@ +usedef @*/