rtcm3.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 Swift Navigation Inc.
00003  * Contact: Fergus Noble <fergus@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 <math.h>
00014 
00015 #include "bits.h"
00016 #include "edc.h"
00017 #include "rtcm3.h"
00018 
00019 #define RTCM3_PREAMBLE 0xD3 
00020 #define PRUNIT_GPS 299792.458 
00022 #define CLIGHT  299792458.0         /* speed of light (m/s) */
00023 #define FREQ1   1.57542e9           /* L1/E1  frequency (Hz) */
00024 #define LAMBDA1 (CLIGHT / FREQ1)
00025 
00046 s16 rtcm3_check_frame(u8 *buff)
00047 {
00048   /* Check preamble byte. */
00049   u8 preamble = getbitu(buff, 0, 8);
00050   if (preamble != RTCM3_PREAMBLE)
00051     return -1;
00052 
00053   s16 len = getbitu(buff, 14, 10);
00054 
00055   /* Calculate CRC of frame header and data message. */
00056   u32 crc_calc = crc24q(buff, len + 3, 0);
00057 
00058   /* Check CRC in frame. */
00059   u32 crc_frame = getbitu(buff, (len+3)*8, 24);
00060 
00061   if (crc_calc != crc_frame)
00062     return -2;
00063 
00064   return len;
00065 }
00066 
00084 s8 rtcm3_write_frame(u16 len, u8 *buff)
00085 {
00086   if (len > 1023)
00087     return -1;
00088 
00089   /* Set preamble, reserved and length bits. */
00090   setbitu(buff, 0, 8, RTCM3_PREAMBLE);
00091   setbitu(buff, 8, 6, 0);
00092   setbitu(buff, 14, 10, len);
00093 
00094   /* Calculate CRC of frame header and data message. */
00095   u32 crc = crc24q(buff, len + 3, 0);
00096 
00097   /* Write CRC to end of frame. */
00098   setbitu(buff, (len+3)*8, 24, crc);
00099 
00100   return 0;
00101 }
00102 
00147 void rtcm3_write_header(u8 *buff, u16 type, u16 id, gps_time_t t,
00148                         u8 sync, u8 n_sat, u8 div_free, u8 smooth)
00149 {
00150   setbitu(buff, 0, 12, type);
00151   setbitu(buff, 12, 12, id);
00152   setbitu(buff, 24, 30, round(t.tow*1e3));
00153   setbitu(buff, 54, 1, sync);
00154   setbitu(buff, 55, 5, n_sat);
00155   setbitu(buff, 60, 1, div_free);
00156   setbitu(buff, 61, 3, smooth);
00157 }
00158 
00177 void rtcm3_read_header(u8 *buff, u16 *type, u16 *id, double *tow,
00178                        u8 *sync, u8 *n_sat, u8 *div_free, u8 *smooth)
00179 {
00180   *type = getbitu(buff, 0, 12);
00181   *id = getbitu(buff, 12, 12);
00182   *tow = getbitu(buff, 24, 30) / 1e3;
00183   *sync = getbitu(buff, 54, 1);
00184   *n_sat = getbitu(buff, 55, 5);
00185   *div_free = getbitu(buff, 60, 1);
00186   *smooth = getbitu(buff, 61, 3);
00187 }
00188 
00195 static u8 to_lock_ind(u32 time)
00196 {
00197   if (time < 24)
00198     return time;
00199   if (time < 72)
00200     return (time + 24) / 2;
00201   if (time < 168)
00202     return (time + 120) / 4;
00203   if (time < 360)
00204     return (time + 408) / 8;
00205   if (time < 744)
00206     return (time + 1176) / 16;
00207   if (time < 937)
00208     return (time + 3096) / 32;
00209   return 127;
00210 }
00211 
00218 static u32 from_lock_ind(u8 lock)
00219 {
00220   if (lock < 24)
00221     return lock;
00222   if (lock < 48)
00223     return 2*lock - 24;
00224   if (lock < 72)
00225     return 4*lock - 120;
00226   if (lock < 96)
00227     return 8*lock - 408;
00228   if (lock < 120)
00229     return 16*lock - 1176;
00230   if (lock < 127)
00231     return 32*lock - 3096;
00232   return 937;
00233 }
00234 
00245 static void gen_obs_gps(navigation_measurement_t *nm,
00246                         u8 *amb, u32 *pr, s32 *ppr, u8 *lock, u8 *cnr)
00247 {
00248   /* Calculate GPS Integer L1 Pseudorange Modulus Ambiguity (DF014). */
00249   *amb = (u8)(nm->raw_pseudorange / PRUNIT_GPS);
00250 
00251   /* Calculate GPS L1 Pseudorange (DF011). */
00252   *pr = (u32)lround((nm->raw_pseudorange - *amb * PRUNIT_GPS) / 0.02);
00253 
00254   /* Construct pseudorange value as transmitted. */
00255   double prc = *pr * 0.02 + *amb * PRUNIT_GPS;
00256 
00257   /* L1 phaserange - L1 pseudorange */
00258   double cp_pr = nm->carrier_phase - prc / (CLIGHT / FREQ1);
00259 
00260   /* If the phaserange and pseudorange have diverged close to the limits of the
00261    * data field (20 bits) then we modify the carrier phase by an integer amount
00262    * to bring it back into range an reset the phase lock time to zero to reset
00263    * the integer ambiguity.
00264    * The spec suggests adjusting by 1500 cycles but I calculate the range to be
00265    * +/- 1379 cycles. Limit to just 1000 as that should still be plenty. */
00266   if (fabs(cp_pr) > 1000) {
00267     nm->lock_time = 0;
00268     nm->carrier_phase -= (s32)cp_pr;
00269     cp_pr -= (s32)cp_pr;
00270   }
00271 
00272   /* Calculate GPS L1 PhaseRange – L1 Pseudorange (DF012). */
00273   *ppr = lround(cp_pr * (CLIGHT / FREQ1) / 0.0005);
00274 
00275   if (lock)
00276     *lock = to_lock_ind(nm->lock_time);
00277 
00278   if (cnr)
00279     /* TODO: When we start actually using cnr values then we can directly use
00280      * the value here. */
00281     *cnr = (u8)((10.0*log10(nm->snr) + 40.0) * 4.0);
00282 }
00283 
00296 u16 rtcm3_encode_1002(u8 *buff, u16 id, gps_time_t t, u8 n_sat,
00297                       navigation_measurement_t *nm, u8 sync)
00298 {
00299   rtcm3_write_header(buff, 1002, id, t, sync, n_sat, 0, 0);
00300 
00301   u16 bit = 64; /* Start at end of header. */
00302 
00303   u32 pr;
00304   s32 ppr;
00305   u8 amb, lock, cnr;
00306 
00307   for (u8 i=0; i<n_sat; i++) {
00308     gen_obs_gps(&nm[i], &amb, &pr, &ppr, &lock, &cnr);
00309 
00310     setbitu(buff, bit, 6,  nm[i].prn + 1); bit += 6;
00311     /* TODO: set GPS code indicator if we ever support P(Y) code measurements. */
00312     setbitu(buff, bit, 1,  0);    bit += 1;
00313     setbitu(buff, bit, 24, pr);   bit += 24;
00314     setbits(buff, bit, 20, ppr);  bit += 20;
00315     setbitu(buff, bit, 7,  lock); bit += 7;
00316     setbitu(buff, bit, 8,  amb);  bit += 8;
00317     setbitu(buff, bit, 8,  cnr);  bit += 8;
00318   }
00319 
00320   /* Round number of bits up to nearest whole byte. */
00321   return (bit + 7) / 8;
00322 }
00323 
00337 s8 rtcm3_decode_1002(u8 *buff, u16 *id, double *tow, u8 *n_sat,
00338                      navigation_measurement_t *nm, u8 *sync)
00339 {
00340   u16 type;
00341   u8 div_free, smooth;
00342 
00343   rtcm3_read_header(buff, &type, id, tow, sync, n_sat, &div_free, &smooth);
00344 
00345   if (type != 1002)
00346     /* Unexpected message type. */
00347     return -1;
00348 
00349   /* TODO: Fill in t->wn. */
00350 
00351   if (!nm)
00352     /* No nav meas pointer, probably just interested in
00353      * n_sat so we are all done. */
00354     return 0;
00355 
00356   u16 bit = 64;
00357   for (u8 i=0; i<*n_sat; i++) {
00358     /* TODO: Handle SBAS prns properly, numbered differently in RTCM? */
00359     nm[i].prn = getbitu(buff, bit, 6) - 1; bit += 6;
00360 
00361     u8 code = getbitu(buff, bit, 1); bit += 1;
00362     /* TODO: When we start storing the signal/system etc. properly we can
00363      * store the code flag in the nav meas struct. */
00364     if (code == 1)
00365       /* P(Y) code not currently supported. */
00366       return -2;
00367 
00368     u32 pr = getbitu(buff, bit,24); bit += 24;
00369     s32 ppr = getbits(buff, bit,20); bit += 20;
00370     u8 lock = getbitu(buff, bit, 7); bit += 7;
00371     u8 amb = getbitu(buff, bit, 8); bit += 8;
00372     u8 cnr = getbitu(buff, bit, 8); bit += 8;
00373 
00374     nm[i].raw_pseudorange = 0.02*pr + PRUNIT_GPS*amb;
00375     nm[i].carrier_phase = (nm[i].raw_pseudorange + 0.0005*ppr) / (CLIGHT / FREQ1);
00376     nm[i].lock_time = from_lock_ind(lock);
00377     nm[i].snr = pow(10.0, ((cnr / 4.0) - 40.0) / 10.0);
00378   }
00379 
00380   return 0;
00381 }
00382 
00383 


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