nav_msg.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 Swift Navigation Inc.
00003  * Contact: Henry Hallam <henry@swift-nav.com>
00004  *
00005  * This source is subject to the license found in the file 'LICENSE' which must
00006  * be be distributed together with this source. All other rights reserved.
00007  *
00008  * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
00009  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
00010  * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
00011  */
00012 
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include <math.h>
00016 
00017 #include "constants.h"
00018 #include "nav_msg.h"
00019 
00020 #define NAV_MSG_BIT_PHASE_THRES 5
00021 
00022 void nav_msg_init(nav_msg_t *n)
00023 {
00024   /* Initialize the necessary parts of the nav message state structure. */
00025   n->subframe_bit_index = 0;
00026   n->bit_phase = 0;
00027   n->bit_phase_ref = 0;
00028   n->bit_phase_count = 0;
00029   n->nav_bit_integrate = 0;
00030   n->subframe_start_index = 0;
00031   memset(n->subframe_bits, 0, sizeof(n->subframe_bits));
00032   n->next_subframe_id = 1;
00033 }
00034 
00035 u32 extract_word(nav_msg_t *n, u16 bit_index, u8 n_bits, u8 invert)
00036 {
00037   /* Extract a word of n_bits length (n_bits <= 32) at position bit_index into
00038    * the subframe. Takes account of the offset stored in n, and the circular
00039    * nature of the n->subframe_bits buffer. */
00040 
00041   /* Offset for the start of the subframe in the buffer. */
00042   if (n->subframe_start_index) {
00043     if (n->subframe_start_index > 0)
00044       bit_index += n->subframe_start_index; /* Standard. */
00045     else {
00046       bit_index -= n->subframe_start_index; /* Bits are inverse! */
00047       invert = !invert;
00048     }
00049 
00050     bit_index--;
00051   }
00052 
00053   /* Wrap if necessary. */
00054   if (bit_index > NAV_MSG_SUBFRAME_BITS_LEN*32)
00055     bit_index -= NAV_MSG_SUBFRAME_BITS_LEN*32;
00056 
00057   u8 bix_hi = bit_index >> 5;
00058   u8 bix_lo = bit_index & 0x1F;
00059   u32 word = n->subframe_bits[bix_hi] << bix_lo;
00060 
00061   if (bix_lo) {
00062     bix_hi++;
00063     if (bix_hi == NAV_MSG_SUBFRAME_BITS_LEN)
00064       bix_hi = 0;
00065     word |=  n->subframe_bits[bix_hi] >> (32 - bix_lo);
00066   }
00067 
00068   if (invert)
00069     word = ~word;
00070 
00071   return word >> (32 - n_bits);
00072 }
00073 
00074 
00075 s32 nav_msg_update(nav_msg_t *n, s32 corr_prompt_real)
00076 {
00077   /* Called once per tracking loop update (atm fixed at 1 PRN [1 ms]). Performs
00078    * the necessary steps to recover the nav bit clock, store the nav bits and
00079    * decode them. */
00080 
00081   s32 TOW_ms = -1;
00082 
00083   /* Do we have bit phase lock yet? (Do we know which of the 20 possible PRN
00084    * offsets corresponds to the nav bit edges?) */
00085   n->bit_phase++;
00086   n->bit_phase %= 20;
00087 
00088   if (n->bit_phase_count < NAV_MSG_BIT_PHASE_THRES) {
00089 
00090     /* No bit phase lock yet. */
00091     if ((n->nav_bit_integrate > 0) != (corr_prompt_real > 0)) {
00092       /* Edge detected. */
00093       if (n->bit_phase == n->bit_phase_ref)
00094         /* This edge came N*20 ms after the last one. */
00095         n->bit_phase_count++;
00096       else {
00097         /* Store the bit phase hypothesis. */
00098         n->bit_phase_ref = n->bit_phase;
00099         n->bit_phase_count = 1;
00100       }
00101     }
00102     /* Store the correlation for next time. */
00103     n->nav_bit_integrate = corr_prompt_real;
00104 
00105   } else {
00106 
00107     /* We have bit phase lock. */
00108     if (n->bit_phase != n->bit_phase_ref) {
00109       /* Sum the correlations over the 20 ms bit period. */
00110       n->nav_bit_integrate += corr_prompt_real;
00111     } else {
00112       /* Dump the nav bit, i.e. determine the sign of the correlation over the
00113        * nav bit period. */
00114 
00115       /* Is bit 1? */
00116       if (n->nav_bit_integrate > 0) {
00117         n->subframe_bits[n->subframe_bit_index >> 5] |= \
00118           1 << (31 - (n->subframe_bit_index & 0x1F));
00119       } else {
00120         /* Integrated correlation is negative, so bit is 0. */
00121         n->subframe_bits[n->subframe_bit_index >> 5] &= \
00122           ~(1 << (31 - (n->subframe_bit_index & 0x1F)));
00123       }
00124 
00125       /* Zero the integrator for the next nav bit. */
00126       n->nav_bit_integrate = 0;
00127 
00128       n->subframe_bit_index++;
00129       if (n->subframe_bit_index == NAV_MSG_SUBFRAME_BITS_LEN*32)
00130         n->subframe_bit_index = 0;
00131 
00132       /* Yo dawg, are we still looking for the preamble? */
00133       if (!n->subframe_start_index) {
00134         /* We're going to look for the preamble at a time 360 nav bits ago,
00135          * then again 60 nav bits ago. */
00136         #define SUBFRAME_START_BUFFER_OFFSET (NAV_MSG_SUBFRAME_BITS_LEN*32 - 360)
00137 
00138         /* Check whether there's a preamble at the start of the circular
00139          * subframe_bits buffer. */
00140         u8 preamble_candidate = extract_word(n, n->subframe_bit_index + SUBFRAME_START_BUFFER_OFFSET, 8, 0);
00141 
00142         if (preamble_candidate == 0x8B) {
00143            n->subframe_start_index = n->subframe_bit_index + SUBFRAME_START_BUFFER_OFFSET + 1;
00144         }
00145         else if (preamble_candidate == 0x74) {
00146            n->subframe_start_index = -(n->subframe_bit_index + SUBFRAME_START_BUFFER_OFFSET + 1);
00147         }
00148 
00149         if (n->subframe_start_index) {
00150           // Looks like we found a preamble, but let's confirm.
00151           if (extract_word(n, 300, 8, 0) == 0x8B) {
00152             // There's another preamble in the following subframe.  Looks good so far.
00153             // Extract the TOW:
00154 
00155             unsigned int TOW_trunc = extract_word(n,30,17,extract_word(n,29,1,0)); // bit 29 is D30* for the second word, where the TOW resides.
00156             TOW_trunc++;  // Increment it, to see what we expect at the start of the next subframe
00157             if (TOW_trunc >= 7*24*60*10)  // Handle end of week rollover
00158               TOW_trunc = 0;
00159 
00160             if (TOW_trunc == extract_word(n,330,17,extract_word(n,329,1,0))) {
00161               // We got two appropriately spaced preambles, and two matching TOW counts.  Pretty certain now.
00162 
00163               // The TOW in the message is for the start of the NEXT subframe.
00164               // That is, 240 nav bits' time from now, since we are 60 nav bits into the second subframe that we recorded.
00165               if (TOW_trunc)
00166                 TOW_ms = TOW_trunc * 6000 - (300-60)*20;
00167               else  // end of week special case
00168                 TOW_ms = 7*24*60*60*1000 - (300-60)*20;
00169               //printf("TOW = hh:%02d:%02d.%03d\n", (int) (TOW_ms / 60000 % 60), (int)(TOW_ms / 1000 % 60), (int)(TOW_ms % 1000));
00170 
00171             } else
00172               n->subframe_start_index = 0;  // the TOW counts didn't match - disregard.
00173           } else
00174             n->subframe_start_index = 0;    // didn't find a second preamble in the right spot - disregard.
00175         }
00176       }
00177     }
00178   }
00179   return TOW_ms;
00180 }
00181 
00182 
00183 int parity(u32 x)
00184 {
00185   /* Returns 1 if there are an odd number of bits set. */
00186   x ^= x >> 1;
00187   x ^= x >> 2;
00188   x ^= x >> 4;
00189   x ^= x >> 8;
00190   x ^= x >> 16;
00191   return (x & 1);
00192 }
00193 
00194 int nav_parity(u32 *word) {
00195 // expects a word where MSB = D29*, bit 30 = D30*, bit 29 = D1, ... LSB = D30 as described in IS-GPS-200E Table 20-XIV
00196 // Inverts the bits if necessary, and checks the parity.
00197 // Returns 0 for success, 1 for fail.
00198 
00199   if (*word & 1<<30)     // inspect D30*
00200     *word ^= 0x3FFFFFC0; // invert all the data bits!
00201 
00202  // printf("w=%08X  ",(unsigned int )word);
00203 
00204   if (parity(*word & 0xBB1F34A0 /* 0b10111011000111110011010010100000 */)) // check d25 (see IS-GPS-200E Table 20-XIV)
00205     return 25;
00206 
00207   if (parity(*word & 0x5D8F9A50 /* 0b01011101100011111001101001010000 */)) // check d26
00208     return 26;
00209 
00210   if (parity(*word & 0xAEC7CD08 /* 0b10101110110001111100110100001000 */)) // check d27
00211     return 27;
00212 
00213   if (parity(*word & 0x5763E684 /* 0b01010111011000111110011010000100 */)) // check d28
00214     return 28;
00215 
00216   if (parity(*word & 0x6BB1F342 /* 0b01101011101100011111001101000010 */)) // check d29
00217     return 29;
00218 
00219   if (parity(*word & 0x8B7A89C1 /* 0b10001011011110101000100111000001 */)) // check d30
00220     return 30;
00221 
00222   return 0;
00223 }
00224 
00225 bool subframe_ready(nav_msg_t *n) {
00226   return (n->subframe_start_index != 0);
00227 }
00228 
00229 s8 process_subframe(nav_msg_t *n, ephemeris_t *e) {
00230   // Check parity and parse out the ephemeris from the most recently received subframe
00231 
00232   // First things first - check the parity, and invert bits if necessary.
00233   // process the data, skipping the first word, TLM, and starting with HOW
00234 
00235   // printf("  %d  ", (n->subframe_start_index > 0));
00236 
00237   /* TODO: Check if inverted has changed and detect half cycle slip. */
00238   if (n->inverted != (n->subframe_start_index < 0))
00239     printf("Nav phase flip\n");
00240   n->inverted = (n->subframe_start_index < 0);
00241 
00242   if (!e) {
00243     printf(" process_subframe: CALLED WITH e = NULL!\n");
00244     n->subframe_start_index = 0;  // Mark the subframe as processed
00245     n->next_subframe_id = 1;      // Make sure we start again next time
00246     return -1;
00247   }
00248   u32 sf_word2 = extract_word(n, 28, 32, 0);
00249   if (nav_parity(&sf_word2)) {
00250       printf("SUBFRAME PARITY ERROR (word 2)\n");
00251       n->subframe_start_index = 0;  // Mark the subframe as processed
00252       n->next_subframe_id = 1;      // Make sure we start again next time
00253       return -2;
00254   }
00255 
00256   u8 sf_id = sf_word2 >> 8 & 0x07;    // Which of 5 possible subframes is it?
00257 
00258   /*printf("sf_id = %d, nsf = %d\n",sf_id, n->next_subframe_id);*/
00259 
00260   if (sf_id <= 3 && sf_id == n->next_subframe_id) {  // Is it the one that we want next?
00261 
00262     for (int w = 0; w < 8; w++) {   // For words 3..10
00263       n->frame_words[sf_id-1][w] = extract_word(n, 30*(w+2) - 2, 32, 0);    // Get the bits
00264       // MSBs are D29* and D30*.  LSBs are D1...D30
00265       if (nav_parity(&n->frame_words[sf_id-1][w])) {  // Check parity and invert bits if D30*
00266         printf("SUBFRAME PARITY ERROR (word %d)\n", w+3);
00267         n->next_subframe_id = 1;      // Make sure we start again next time
00268         n->subframe_start_index = 0;  // Mark the subframe as processed
00269         return -3;
00270       }
00271     }
00272     n->subframe_start_index = 0;  // Mark the subframe as processed
00273     n->next_subframe_id++;
00274 
00275     if (sf_id == 3) {
00276       // Got all of subframes 1 to 3
00277       n->next_subframe_id = 1;      // Make sure we start again next time
00278 
00279       // Now let's actually go through the parameters...
00280 
00281       // These unions facilitate signed/unsigned conversion and sign extension
00282       union {
00283         s8 s8;
00284         u8 u8;
00285       } onebyte;
00286 
00287       union
00288       {
00289         s16 s16;
00290         u16 u16;
00291       } twobyte;
00292 
00293       union
00294       {
00295         s32 s32;
00296         u32 u32;
00297       } fourbyte;
00298 
00299       // Subframe 1: SV health, T_GD, t_oc, a_f2, a_f1, a_f0
00300 
00301       e->toe.wn = (n->frame_words[0][3-3] >> (30-10) & 0x3FF);       // GPS week number (mod 1024): Word 3, bits 20-30
00302       e->toe.wn += GPS_WEEK_CYCLE*1024;
00303       e->toc.wn = e->toe.wn;
00304 
00305       e->healthy = !(n->frame_words[0][3-3] >> (30-17) & 1);     // Health flag: Word 3, bit 17
00306 
00307       onebyte.u8 = n->frame_words[0][7-3] >> (30-24) & 0xFF;  // t_gd: Word 7, bits 17-24
00308       e->tgd = onebyte.s8 * pow(2,-31);
00309 
00310       e->toc.tow = (n->frame_words[0][8-3] >> (30-24) & 0xFFFF) * 16;   // t_oc: Word 8, bits 8-24
00311 
00312       onebyte.u8 = n->frame_words[0][9-3] >> (30-8) & 0xFF;         // a_f2: Word 9, bits 1-8
00313       e->af2 = onebyte.s8 * pow(2,-55);
00314 
00315       twobyte.u16 = n->frame_words[0][9-3] >> (30-24) & 0xFFFF;     // a_f1: Word 9, bits 9-24
00316       e->af1 = twobyte.s16 * pow(2,-43);
00317 
00318       fourbyte.u32 = n->frame_words[0][10-3] >> (30-22) & 0x3FFFFF; // a_f0: Word 10, bits 1-22
00319       fourbyte.u32 <<= 10; // Shift to the left for sign extension
00320       fourbyte.s32 >>= 10; // Carry the sign bit back down and reduce to signed 22 bit value
00321       e->af0 = fourbyte.s32 * pow(2,-31);
00322 
00323 
00324       // Subframe 2: crs, dn, m0, cuc, ecc, cus, sqrta, toe
00325 
00326       twobyte.u16 = n->frame_words[1][3-3] >> (30-24) & 0xFFFF;     // crs: Word 3, bits 9-24
00327       e->crs = twobyte.s16 * pow(2,-5);
00328 
00329       twobyte.u16 = n->frame_words[1][4-3] >> (30-16) & 0xFFFF;     // dn: Word 4, bits 1-16
00330       e->dn = twobyte.s16 * pow(2,-43) * GPS_PI;
00331 
00332       fourbyte.u32 = ((n->frame_words[1][4-3] >> (30-24) & 0xFF) << 24) // m0: Word 4, bits 17-24
00333                   | (n->frame_words[1][5-3] >> (30-24) & 0xFFFFFF);     // and word 5, bits 1-24
00334       e->m0 = fourbyte.s32 * pow(2,-31) * GPS_PI;
00335 
00336       twobyte.u16 = n->frame_words[1][6-3] >> (30-16) & 0xFFFF;    // cuc: Word 6, bits 1-16
00337       e->cuc = twobyte.s16 * pow(2,-29);
00338 
00339       fourbyte.u32 = ((n->frame_words[1][6-3] >> (30-24) & 0xFF) << 24) // ecc: Word 6, bits 17-24
00340                   | (n->frame_words[1][7-3] >> (30-24) & 0xFFFFFF);     // and word 7, bits 1-24
00341       e->ecc = fourbyte.u32 * pow(2,-33);
00342 
00343 
00344       twobyte.u16 = n->frame_words[1][8-3] >> (30-16) & 0xFFFF;   // cus: Word 8, bits 1-16
00345       e->cus = twobyte.s16 * pow(2,-29);
00346 
00347 
00348       fourbyte.u32 = ((n->frame_words[1][8-3] >> (30-24) & 0xFF) << 24) // sqrta: Word 8, bits 17-24
00349                   | (n->frame_words[1][9-3] >> (30-24) & 0xFFFFFF);     // and word 9, bits 1-24
00350       e->sqrta = fourbyte.u32 * pow(2,-19);
00351 
00352       e->toe.tow = (n->frame_words[1][10-3] >> (30-16) & 0xFFFF) * 16;   // t_oe: Word 10, bits 1-16
00353 
00354 
00355       // Subframe 3: cic, omega0, cis, inc, crc, w, omegadot, inc_dot
00356 
00357       twobyte.u16 = n->frame_words[2][3-3] >> (30-16) & 0xFFFF;   // cic: Word 3, bits 1-16
00358       e->cic = twobyte.s16 * pow(2,-29);
00359 
00360       fourbyte.u32 = ((n->frame_words[2][3-3] >> (30-24) & 0xFF) << 24) // omega0: Word 3, bits 17-24
00361                   | (n->frame_words[2][4-3] >> (30-24) & 0xFFFFFF);     // and word 4, bits 1-24
00362       e->omega0 = fourbyte.s32 * pow(2,-31) * GPS_PI;
00363 
00364       twobyte.u16 = n->frame_words[2][5-3] >> (30-16) & 0xFFFF; // cis: Word 5, bits 1-16
00365       e->cis = twobyte.s16 * pow(2,-29);
00366 
00367       fourbyte.u32 = ((n->frame_words[2][5-3] >> (30-24) & 0xFF) << 24) // inc (i0): Word 5, bits 17-24
00368                   | (n->frame_words[2][6-3] >> (30-24) & 0xFFFFFF);     // and word 6, bits 1-24
00369       e->inc = fourbyte.s32 * pow(2,-31) * GPS_PI;
00370 
00371       twobyte.u16 = n->frame_words[2][7-3] >> (30-16) & 0xFFFF; // crc: Word 7, bits 1-16
00372       e->crc = twobyte.s16 * pow(2,-5);
00373 
00374       fourbyte.u32 = ((n->frame_words[2][7-3] >> (30-24) & 0xFF) << 24) // w (omega): Word 7, bits 17-24
00375                   | (n->frame_words[2][8-3] >> (30-24) & 0xFFFFFF);     // and word 8, bits 1-24
00376       e->w = fourbyte.s32 * pow(2,-31) * GPS_PI;
00377 
00378       fourbyte.u32 = n->frame_words[2][9-3] >> (30-24) & 0xFFFFFF;     // Omega_dot: Word 9, bits 1-24
00379       fourbyte.u32 <<= 8; // shift left for sign extension
00380       fourbyte.s32 >>= 8; // sign-extend it
00381       e->omegadot = fourbyte.s32 * pow(2,-43) * GPS_PI;
00382 
00383 
00384       twobyte.u16 = n->frame_words[2][10-3] >> (30-22) & 0x3FFF;  // inc_dot (IDOT): Word 10, bits 9-22
00385       twobyte.u16 <<= 2;
00386       twobyte.s16 >>= 2;  // sign-extend
00387       e->inc_dot = twobyte.s16 * pow(2,-43) * GPS_PI;
00388 
00389 
00390       e->valid = 1;
00391 
00392       /*printf("Health %d\n", e->healthy);*/
00393       /*printf("TGD %16g\n", e->tgd);*/
00394       /*printf("TOC %16u\n", (unsigned int)e->toc);*/
00395       /*printf("af2 %16g\n", e->af2);*/
00396       /*printf("af1 %16g\n", e->af1);*/
00397       /*printf("af0 %16g\n", e->af0);*/
00398       /*printf("CRS %16g\n", e->crs);*/
00399       /*printf("DN %16g\n", e->dn);*/
00400       /*printf("M0 %16g\n", e->m0);*/
00401       /*printf("CUC %16g\n", e->cuc);*/
00402       /*printf("Ecc %16g\n", e->ecc);*/
00403       /*printf("CUS %16g\n", e->cus);*/
00404       /*printf("SQRT A %16g\n", e->sqrta);*/
00405       /*printf("TOE %16u\n", (unsigned int)e->toe);*/
00406       /*printf("CIC %16g\n", e->cic);*/
00407       /*printf("omega0 %16g\n", e->omega0);*/
00408       /*printf("CIS %16g\n", e->cis);*/
00409       /*printf("Inc %16g\n", e->inc);*/
00410       /*printf("CRC %16g\n", e->crc);*/
00411       /*printf("W %16g\n", e->w);*/
00412       /*printf("omegadot %16g\n", e->omegadot);*/
00413       /*printf("inc_dot %16g\n", e->inc_dot);*/
00414       return 1;
00415 
00416     }
00417   } else {  // didn't get the subframe that we want next
00418       n->next_subframe_id = 1;      // Make sure we start again next time
00419       n->subframe_start_index = 0;  // Mark the subframe as processed
00420   }
00421 
00422   return 0;
00423 
00424 
00425 }
00426 


swiftnav
Author(s):
autogenerated on Sat Jun 8 2019 18:55:56