1 /* subframe.c -- interpret satellite subframe data.
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.
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
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
24 int gpsd_interpret_subframe_raw(struct gps_device_t *session,
28 unsigned int preamble, parity;
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.
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.
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
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]);
53 preamble = (words[0] >> 22) & 0xff;
54 if (preamble == 0x8b) { /* preamble is inverted */
55 words[0] ^= 0x3fffffc0; /* invert */
56 } else if (preamble != 0x74) {
58 "50B: gpsd_interpret_subframe_raw: bad preamble 0x%x\n",
62 words[0] = (words[0] >> 6) & 0xffffff;
64 for (i = 1; i < 10; i++) {
66 /* D30* says invert */
67 invert = (words[i] & 0x40000000) ? 1 : 0;
68 /* inverted data, invert it back */
70 words[i] ^= 0x3fffffc0;
72 parity = isgps_parity(words[i]);
73 if (parity != (words[i] & 0x3f)) {
75 "50B: gpsd_interpret_subframe_raw parity fail words[%d] 0x%x != 0x%x\n",
76 i, parity, (words[i] & 0x1));
79 words[i] = (words[i] >> 6) & 0xffffff;
82 gpsd_interpret_subframe(session, words);
86 void gpsd_interpret_subframe(struct gps_device_t *session,
90 * Heavy black magic begins here!
92 * A description of how to decode these bits is at
93 * <http://home-2.worldonline.nl/~samsvl/nav2eu.htm>
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.
100 * To date this code has been tested on iTrax, SiRF and ublox.
102 unsigned int pageid, subframe, data_id, leap, lsf, wnlsf, dn, preamble;
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]);
109 preamble = (unsigned int)((words[0] >> 16) & 0xffL);
110 if (preamble == 0x8b) {
112 words[0] ^= 0xffffff;
114 if (preamble != 0x74) {
115 gpsd_report(LOG_WARN,
116 "50B: gpsd_interpret_subframe bad preamble: 0x%x header 0x%x\n",
120 /* The subframe ID is in the Hand Over Word (page 80) */
121 subframe = ((words[1] >> 2) & 0x07);
123 * Consult the latest revision of IS-GPS-200 for the mapping
124 * between magic SVIDs and pages.
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);
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);
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)
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. */
152 str[j++] = (words[2] >> 8) & 0xff;
153 str[j++] = (words[2]) & 0xff;
155 str[j++] = (words[3] >> 16) & 0xff;
156 str[j++] = (words[3] >> 8) & 0xff;
157 str[j++] = (words[3]) & 0xff;
159 str[j++] = (words[4] >> 16) & 0xff;
160 str[j++] = (words[4] >> 8) & 0xff;
161 str[j++] = (words[4]) & 0xff;
163 str[j++] = (words[5] >> 16) & 0xff;
164 str[j++] = (words[5] >> 8) & 0xff;
165 str[j++] = (words[5]) & 0xff;
167 str[j++] = (words[6] >> 16) & 0xff;
168 str[j++] = (words[6] >> 8) & 0xff;
169 str[j++] = (words[6]) & 0xff;
171 str[j++] = (words[7] >> 16) & 0xff;
172 str[j++] = (words[7] >> 8) & 0xff;
173 str[j++] = (words[7]) & 0xff;
175 str[j++] = (words[8] >> 16) & 0xff;
176 str[j++] = (words[8] >> 8) & 0xff;
177 str[j++] = (words[8]) & 0xff;
179 str[j++] = (words[9] >> 16) & 0xff;
180 str[j++] = (words[9] >> 8) & 0xff;
183 gpsd_report(LOG_INF, "50B: gps system message is %s\n", str);
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 */
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.
197 if (LEAP_SECONDS > leap) {
198 /* something wrong */
199 gpsd_report(LOG_ERROR, "50B: Invalid leap_seconds: %d\n",
202 session->context->valid &= ~LEAP_SECOND_VALID;
205 "50B: leap-seconds: %d, lsf: %d, WNlsf: %d, DN: %d \n",
206 leap, lsf, wnlsf, dn);
207 session->context->valid |= LEAP_SECOND_VALID;
209 gpsd_report(LOG_PROG, "50B: leap-second change coming\n");
212 session->context->leap_seconds = (int)leap;