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


enu
Author(s): Mike Purvis
autogenerated on Sun Oct 5 2014 23:44:53