novatel.c

Go to the documentation of this file.
00001 /**
00002 \file    novatel.c
00003 \brief   GNSS core 'c' function library: decoding/encoding NovAtel data.
00004 \author  Glenn D. MacGougan (GDM)
00005 \date    2007-11-29
00006 \since   2006-08-04
00007 
00008 \b REFERENCES \n
00009 - NovAtel OEM4 Command and Log Reference. www.novatel.com.
00010 
00011 \b "LICENSE INFORMATION" \n
00012 Copyright (c) 2007, refer to 'author' doxygen tags \n
00013 All rights reserved. \n
00014 
00015 Redistribution and use in source and binary forms, with or without
00016 modification, are permitted provided the following conditions are met: \n
00017 
00018 - Redistributions of source code must retain the above copyright
00019   notice, this list of conditions and the following disclaimer. \n
00020 - Redistributions in binary form must reproduce the above copyright
00021   notice, this list of conditions and the following disclaimer in the
00022   documentation and/or other materials provided with the distribution. \n
00023 - The name(s) of the contributor(s) may not be used to endorse or promote 
00024   products derived from this software without specific prior written 
00025   permission. \n
00026 
00027 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00028 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00029 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00030 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00031 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00032 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00033 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00034 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00035 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00036 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00037 SUCH DAMAGE.
00038 */
00039 
00040 #include <stdio.h>
00041 #include <memory.h>
00042 #include "gnss_error.h"
00043 #include "novatel.h"
00044 #include "gps.h"
00045 #include "constants.h"
00046 
00047 /// \brief  Compares the received OEM3 message checksum to a calculated value.
00048 /// \return  TRUE if successful (isChecksumValid = TRUE or FALSE), FALSE otherwise, i.e. error condition.
00049 static BOOL NOVATELOEM3_CompareChecksums( 
00050   unsigned char *message,         //!< A pointer to the message buffer beginning with the sync bytes.
00051   const unsigned messageLength,   //!< The length of the message [bytes].
00052   const unsigned messageChecksum, //!< The received crc in the message.
00053   BOOL *isChecksumValid           //!< Is the Checksum valid? Does it match the calculated value.
00054   );
00055 
00056 /// \brief   Calculate the CRC32 for a Novatel binary message. crcData != NULL.
00057 /// \return  The CRC32 value.
00058 static unsigned NOVATEL_CalculateCRC32(                                   
00059   unsigned char *crcData,          //!< A pointer to the data buffer used in the computation of the crc.
00060   const unsigned short dataLength  //!< The length of the data buffer [bytes].  
00061   );   
00062 
00063 
00064 /// \brief   Calculates the CRC32 for a NOVATEL OEM4 message.
00065 /// \return  TRUE if successful (isCRCValid = TRUE or FALSE), FALSE otherwise, i.e. error condition.
00066 static BOOL NOVATEL_CheckCRC32( 
00067   unsigned char *message,             //!< A pointer to the message buffer beginning with the sync bytes.
00068   const unsigned short messageLength, //!< The length of the message.
00069   const unsigned messageCRC,          //!< The received crc in the message.
00070   BOOL *isCRCValid                    //!< Is the CRC valid? Does it match the calculated value.
00071   );
00072 
00073 
00074 static const unsigned NOVATEL_CRC32_Table[256] =
00075 {
00076   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL,
00077   0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
00078   0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L,
00079   0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
00080   0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
00081   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
00082   0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL,
00083   0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
00084   0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L,
00085   0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
00086   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L,
00087   0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
00088   0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL,
00089   0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
00090   0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
00091   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
00092   0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L,
00093   0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
00094   0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL,
00095   0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
00096   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L,
00097   0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
00098   0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L,
00099   0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
00100   0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
00101   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
00102   0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL,
00103   0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
00104   0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L,
00105   0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
00106   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L,
00107   0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
00108   0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL,
00109   0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
00110   0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
00111   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
00112   0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L,
00113   0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
00114   0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL,
00115   0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
00116   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L,
00117   0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
00118   0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
00119 };
00120 
00121 // static 
00122 BOOL NOVATELOEM3_CompareChecksums( 
00123   unsigned char *message,         //!< A pointer to the message buffer beginning with the sync bytes.
00124   const unsigned messageLength,   //!< The length of the message [bytes].
00125   const unsigned messageChecksum, //!< The received crc in the message.
00126   BOOL *isChecksumValid           //!< Is the Checksum valid? Does it match the calculated value.
00127   )
00128 {
00129   unsigned char tmpc;
00130   unsigned char xorVal = 0;
00131   unsigned i = 0;
00132   
00133   if( messageLength < 12 )
00134     return FALSE;
00135 
00136   tmpc = message[3];
00137   message[3] = 0; // Set the checksum in the message to 0 as it was originally calculated.
00138 
00139   // Compute the checksum
00140   for( xorVal = 0; i < messageLength; i++ )
00141   {
00142     xorVal ^= message[i];
00143   }
00144   
00145   // Reset the original data to its true state.
00146   message[3] = tmpc;
00147 
00148   if( xorVal == messageChecksum )
00149     *isChecksumValid = TRUE;
00150   else
00151     *isChecksumValid = FALSE;
00152 
00153   return TRUE;
00154 }                                
00155 
00156 
00157 // static 
00158 unsigned NOVATEL_CalculateCRC32(                                   
00159   unsigned char *crcData,          //!< A pointer to the data buffer used in the computation of the crc.
00160   const unsigned short dataLength  //!< The length of the data buffer [bytes].  
00161   )   
00162 {
00163   unsigned i;
00164   unsigned crc = 0;  
00165   for( i = 0; i < dataLength; i++ )   
00166     crc = NOVATEL_CRC32_Table[(crc ^ crcData[i]) & 0xFF] ^ (crc >> 8);
00167   return crc;
00168 }
00169 
00170 
00171 // static
00172 BOOL NOVATEL_CheckCRC32( 
00173   unsigned char *message,             //!< A pointer to the message buffer beginning with the sync bytes.
00174   const unsigned short messageLength, //!< The length of the message [bytes].
00175   const unsigned messageCRC,          //!< The received crc in the message.
00176   BOOL *isCRCValid                    //!< Is the CRC valid? Does it match the calculated value.
00177   )
00178 {
00179   unsigned crc = 0; // The calculated crc.
00180 
00181   if( message == NULL )
00182   {
00183     GNSS_ERROR_MSG( "if( message == NULL )" );
00184     return FALSE;
00185   }
00186   
00187   // Calculate the crc.
00188   crc = NOVATEL_CalculateCRC32( message, messageLength-4 );
00189   
00190   *isCRCValid = FALSE;
00191 
00192   if( messageCRC != crc )
00193     *isCRCValid = FALSE;
00194   else
00195     *isCRCValid = TRUE;
00196 
00197   return TRUE;
00198 }
00199 
00200 
00201 
00202 
00203 BOOL NOVATELOEM3_FindNextMessageInFile(
00204   FILE *fid,                       //!< A file pointer to an open file (input).
00205   unsigned char *message,          //!< A message buffer in which to place the message found (input/output).
00206   const unsigned maxMessageLength, //!< The maximum size of the message buffer (input).
00207   BOOL *wasEndOfFileReached,       //!< Has the end of the file been reached (output).
00208   BOOL *wasMessageFound,           //!< Was a valid message found (output).
00209   unsigned *filePosition,          //!< The file position for the start of the message found (output).
00210   unsigned *messageLength,         //!< The length of the entire message found and stored in the message buffer (output).
00211   unsigned *messageID,             //!< The message ID of the message found.
00212   unsigned *numberBadChecksums     //!< The number of bad checksum values found. (checksum fails or mistaken messages).
00213   )
00214 {
00215   unsigned i = 0;                  // The index into the message buffer.
00216   unsigned char sync[3];           // 0xAA 0x44 0x11
00217   unsigned byteCount = 0;          // This indicates the number of bytes read by fread().
00218   unsigned dataLength = 0;         // The length of the data portion of the message. i.e. Entire message length - 12.
00219   unsigned msgLength = 0;          // The entire length of the current message being examined.
00220   int fpos = 0;                    // A signed file position (needs sign for error checking).
00221   unsigned char rx_checksum = 0;   // The received message checksum value.
00222   BOOL startSearch = TRUE;         // A boolean to indicate that the sync search is occurring.
00223   BOOL isChecksumValid = FALSE;    // A boolean to indicate if the checksum is valid. Does it match the calculated value.
00224 
00225   const unsigned char headerLength = 12;  // The length of the message header [bytes]. Fixed at 12.
00226   
00227   // Initialize the output parameters.
00228   *wasEndOfFileReached = FALSE;
00229   *wasMessageFound     = 0;
00230   *filePosition        = 0;
00231   *messageLength       = 0;
00232   *messageID           = 0;
00233   *numberBadChecksums  = 0;
00234 
00235   // Ensure that the file pointer is valid.
00236   if( fid == NULL )
00237   {
00238     GNSS_ERROR_MSG( "if( fid == NULL )" );
00239     return FALSE;
00240   }
00241 
00242   if( message == NULL )
00243   {
00244     GNSS_ERROR_MSG( "if( message == NULL )" );
00245     return FALSE;
00246   }
00247 
00248   // Ensure that the maximum message length is appropriate.
00249   if( maxMessageLength < 12 ) // at least the header.
00250   {
00251     GNSS_ERROR_MSG( "if( maxMessageLength < 12 )" );
00252     return FALSE;
00253   }
00254   
00255   // Ensure that the file pointer is not at the end of the file.
00256   if( feof(fid) )
00257   {
00258     *wasEndOfFileReached = TRUE;
00259     return TRUE;
00260   }
00261   
00262   while( !(*wasEndOfFileReached) && !(*wasMessageFound) )
00263   {
00264     if( startSearch )
00265     {
00266       // Get the first two sync bytes.
00267       sync[0] = (unsigned char)fgetc( fid );
00268       if( feof( fid ) )
00269       {
00270         *wasEndOfFileReached = TRUE;
00271         return TRUE;
00272       }
00273 
00274       sync[1] = (unsigned char)fgetc( fid );
00275       if( feof( fid ) )
00276       {
00277         *wasEndOfFileReached = TRUE;
00278         return TRUE;
00279       }  
00280 
00281       startSearch = FALSE;
00282     }
00283 
00284     // Get the last sync byte.
00285     sync[2] = (unsigned char)fgetc( fid );
00286     if( feof( fid ) )
00287     {
00288       *wasEndOfFileReached = TRUE;
00289       return TRUE;
00290     }
00291 
00292     // Check the full sync.
00293     if( sync[0] == 0xAA && sync[1] == 0x44 && sync[2] == 0x11 )
00294     {
00295       // Found a potential message.
00296       i = 0;
00297       message[i] = sync[0]; i++;
00298       message[i] = sync[1]; i++;
00299       message[i] = sync[2]; i++;
00300 
00301       // Determine the file position of the start of the message
00302       fpos = ftell(fid);
00303       if( fpos < 2 ) // check less than 2 because we are at least 3 bytes into the file
00304       {
00305         GNSS_ERROR_MSG( "if( fpos < 2 )" );
00306         return FALSE;
00307       }
00308       *filePosition = fpos - 3; // The start of the message sync.
00309 
00310       // Get the rest of the header.
00311       rx_checksum = (unsigned char)fgetc( fid );
00312       if( feof( fid ) )
00313       {
00314         *wasEndOfFileReached = TRUE;
00315         return TRUE;
00316       }
00317       message[i] = rx_checksum;
00318       i++;
00319 
00320       // Get the message ID.
00321       byteCount = (int)fread( &(message[i]), sizeof(unsigned char), 4, fid );
00322       if( byteCount != 4 )
00323       {
00324         *wasEndOfFileReached = TRUE;
00325         return TRUE;
00326       }
00327       // Determine the 4 byte message ID.
00328       *messageID  = message[i];       i++;
00329       *messageID |= message[i] << 8;  i++;
00330       *messageID |= message[i] << 16; i++;
00331       *messageID |= message[i] << 24; i++;     
00332 
00333       // Get the message byte count.
00334       byteCount = (int)fread( &(message[i]), sizeof(unsigned char), 4, fid );
00335       if( byteCount != 4 )
00336       {
00337         *wasEndOfFileReached = TRUE;
00338         return TRUE;
00339       }
00340       // Determine the 4 byte message byte count (includes the header bytes).
00341       msgLength  = message[i];       i++;
00342       msgLength |= message[i] << 8;  i++;
00343       msgLength |= message[i] << 16; i++;
00344       msgLength |= message[i] << 24; i++;
00345 
00346       // determine the length of the data only.
00347       dataLength = msgLength - headerLength;
00348 
00349       // Check that the entire message length will fit in the message buffer.
00350       if( msgLength > maxMessageLength )
00351       {
00352         // Perhaps the data length was bad.
00353         // Start searching again after the sync that was found.
00354         // Set the file position to the last of the three sync bytes.
00355         if( fseek( fid, fpos, SEEK_SET ) != 0 )
00356         {
00357           // The seek failed.
00358           GNSS_ERROR_MSG( "fseek failed." );            
00359           return FALSE;
00360         }
00361         startSearch = TRUE;
00362         continue;
00363       }
00364 
00365       // Get the data part of the message.
00366       // advance i to the start of the data
00367       i = headerLength;
00368       byteCount = (int)fread( &(message[i]), sizeof(unsigned char), dataLength, fid );
00369       if( byteCount != dataLength )
00370       {
00371         // Either a message has an invalid length or a message was cut off.
00372         // We do not want to read over any valid message so start the search again.
00373         // Start searching again after the sync that was found.
00374         // Set the file position to the last of the three sync bytes.
00375         if( fseek( fid, fpos, SEEK_SET ) != 0 )
00376         {
00377           // The seek failed.
00378           GNSS_ERROR_MSG( "fseek failed." );
00379           return FALSE;
00380         }
00381         startSearch = TRUE;
00382         continue;
00383       }
00384       i += dataLength;
00385 
00386       // Compare the received message checksum with the calculated checksum.
00387       if( !NOVATELOEM3_CompareChecksums( message, msgLength, rx_checksum, &isChecksumValid ) )
00388       {
00389         GNSS_ERROR_MSG( "NOVATELOEM3_CompareChecksums returned FALSE." );
00390         return FALSE;
00391       }
00392       if( !isChecksumValid )
00393       {
00394         *numberBadChecksums += 1;
00395 
00396         // Start searching again after the sync that was found.
00397         // Set the file position to the last of the three sync bytes.
00398         if( fseek( fid, fpos, SEEK_SET ) != 0 )
00399         {
00400           // The seek failed.
00401           GNSS_ERROR_MSG( "fseek failed." );          
00402           return FALSE;
00403         }
00404         startSearch = TRUE;
00405         continue;
00406       }
00407 
00408       *wasMessageFound = TRUE;
00409       *messageLength = msgLength;
00410       break;
00411     }
00412     else
00413     {
00414       // Shift the first two bytes of the sync.
00415       sync[0] = sync[1];
00416       sync[1] = sync[2];
00417     }
00418   }
00419   return TRUE;
00420 }
00421 
00422 
00423 
00424 BOOL NOVATELOEM3_FindNextMessageInBuffer(
00425   unsigned char *buffer,           //!< A pointer to a buffer containing input data.
00426   const unsigned bufferLength,     //!< The length of the valid data contained in the buffer.
00427   unsigned char *message,          //!< A message buffer in which to place the message found (input/output).
00428   const unsigned maxMessageLength, //!< The maximum size of the message buffer (input).
00429   BOOL *wasEndOfBufferReached,     //!< Has the end of the buffer been reached (output).
00430   BOOL *wasMessageFound,           //!< Was a valid message found (output).
00431   unsigned *startPosition,         //!< The index into the buffer for the start of the message found (output).
00432   unsigned *messageLength,         //!< The length of the entire message found and stored in the message buffer (output).
00433   unsigned *messageID,             //!< The message ID of the message found.
00434   unsigned *numberBadChecksums     //!< The number of bad checksum values found. (checksum fails or mistaken messages).
00435   )
00436 {
00437   unsigned bi = 0;                 // The index into the input buffer.
00438   unsigned i = 0;                  // The index into the message buffer.
00439   unsigned char sync[3];           // 0xAA 0x44 0x11
00440   unsigned dataLength = 0;         // The length of the data portion of the message. i.e. Entire message length - 12.
00441   unsigned msgLength = 0;          // The entire length of the current message being examined.
00442   int bpos = 0;                    // An index into the buffer (needs sign for error checking).
00443   unsigned char rx_checksum = 0;   // The received message checksum value.
00444   BOOL startSearch = TRUE;         // A boolean to indicate that the sync search is occurring.
00445   BOOL isChecksumValid = FALSE;    // A boolean to indicate if the checksum is valid. Does it match the calculated value.
00446 
00447   const unsigned char headerLength = 12;  // The length of the message header [bytes]. Fixed at 12.
00448   
00449   // Initialize the output parameters.
00450   *wasEndOfBufferReached = FALSE;
00451   *wasMessageFound     = 0;
00452   *startPosition       = 0;
00453   *messageLength       = 0;
00454   *messageID           = 0;
00455   *numberBadChecksums  = 0;
00456 
00457   // Ensure that the buffer pointer is valid.
00458   if( buffer == NULL )
00459   {
00460     GNSS_ERROR_MSG( "if( fid == NULL )" );
00461     return FALSE;
00462   }
00463 
00464   if( message == NULL )
00465   {
00466     GNSS_ERROR_MSG( "if( message == NULL )" );
00467     return FALSE;
00468   }
00469 
00470   // Ensure that the maximum message length is appropriate.
00471   if( maxMessageLength < 12 ) // at least the header.
00472   {
00473     GNSS_ERROR_MSG( "if( maxMessageLength < 12 )" );
00474     return FALSE;
00475   }
00476   
00477   while( !(*wasEndOfBufferReached) && !(*wasMessageFound) )
00478   {
00479     if( startSearch )
00480     {
00481       // Get the first two sync bytes.
00482       sync[0] = buffer[bi]; bi++;
00483       if( bi >= bufferLength )
00484       {
00485         *wasEndOfBufferReached = TRUE;
00486         return TRUE;
00487       }
00488 
00489       sync[1] = buffer[bi]; bi++;
00490       if( bi >= bufferLength )
00491       {
00492         *wasEndOfBufferReached = TRUE;
00493         return TRUE;
00494       }  
00495       startSearch = FALSE;
00496     }
00497 
00498     // Get the last sync byte.
00499     sync[2] = buffer[bi]; bi++;
00500     if( bi >= bufferLength )
00501     {
00502       *wasEndOfBufferReached = TRUE;
00503       return TRUE;
00504     }
00505 
00506     // Check the full sync.
00507     if( sync[0] == 0xAA && sync[1] == 0x44 && sync[2] == 0x11 )
00508     {
00509       // Found a potential message.
00510       i = 0;
00511       message[i] = sync[0]; i++;
00512       message[i] = sync[1]; i++;
00513       message[i] = sync[2]; i++;
00514 
00515       // Determine the file position of the start of the message
00516       bpos = bi;
00517       *startPosition = bi - 3; // The start of the message sync.
00518 
00519       // Get the rest of the header.
00520       rx_checksum = buffer[bi]; bi++;
00521       if( bi > bufferLength )
00522       {
00523         *wasEndOfBufferReached = TRUE;
00524         return TRUE;
00525       }
00526       message[i] = rx_checksum;
00527       i++;
00528 
00529       // Get the message ID.
00530       if( bi+4 > bufferLength )
00531       {
00532         *wasEndOfBufferReached = TRUE;
00533         return TRUE;
00534       }
00535       memcpy( &message[i], buffer+bi, 4 ); 
00536       bi+=4;
00537       
00538       // Determine the 4 byte message ID.
00539       *messageID  = message[i];       i++;
00540       *messageID |= message[i] << 8;  i++;
00541       *messageID |= message[i] << 16; i++;
00542       *messageID |= message[i] << 24; i++;     
00543 
00544       // Get the message byte count.
00545       if( bi+4 > bufferLength )
00546       {
00547         *wasEndOfBufferReached = TRUE;
00548         return TRUE;
00549       }
00550       memcpy( &message[i], buffer+bi, 4 ); 
00551       bi+=4;
00552       
00553       // Determine the 4 byte message byte count (includes the header bytes).
00554       msgLength  = message[i];       i++;
00555       msgLength |= message[i] << 8;  i++;
00556       msgLength |= message[i] << 16; i++;
00557       msgLength |= message[i] << 24; i++;
00558 
00559       // determine the length of the data only.
00560       dataLength = msgLength - headerLength;
00561 
00562       // Check that the entire message length will fit in the message buffer.
00563       if( msgLength > maxMessageLength )
00564       {
00565         // Perhaps the data length was bad.
00566         // Start searching again after the sync that was found.
00567         // Set the buffer index to the last of the three sync bytes.
00568         bi = bpos;        
00569         startSearch = TRUE;
00570         continue;
00571       }
00572 
00573       // Get the data part of the message.
00574       // advance i to the start of the data
00575       i = headerLength;
00576 
00577       if( bi+dataLength > bufferLength )
00578       {
00579         *wasEndOfBufferReached = TRUE;
00580         return TRUE;
00581       }
00582       memcpy( &message[i], buffer+bi, dataLength );       
00583       bi+=dataLength;
00584       i += dataLength;
00585 
00586       // Compare the received message checksum with the calculated checksum.
00587       if( !NOVATELOEM3_CompareChecksums( message, msgLength, rx_checksum, &isChecksumValid ) )
00588       {
00589         GNSS_ERROR_MSG( "NOVATELOEM3_CompareChecksums returned FALSE." );
00590         return FALSE;
00591       }
00592       if( !isChecksumValid )
00593       {
00594         *numberBadChecksums += 1;
00595 
00596         // Start searching again after the sync that was found.
00597         // Set the file position to the last of the three sync bytes.
00598         bi = bpos;
00599         startSearch = TRUE;
00600         continue;
00601       }
00602 
00603       *wasMessageFound = TRUE;
00604       *messageLength = msgLength;
00605       break;
00606     }
00607     else
00608     {
00609       // Shift the first two bytes of the sync.
00610       sync[0] = sync[1];
00611       sync[1] = sync[2];
00612     }
00613   }
00614   return TRUE;
00615 }
00616 
00617 
00618 BOOL NOVATELOEM3_DecodeREPB(
00619   const unsigned char *message,           //!< The message buffer containing a complete RANGEB message (input).
00620   const unsigned messageLength,           //!< The length of the entire message (input).
00621   unsigned       *prn,                    //!< The satellite PRN number.
00622   unsigned       *tow,                    //!< The time of week in subframe1, the time of the leading bit edge of subframe 2 [s]
00623   unsigned short *iodc,                   //!< 10 bit issue of data (clock), 8 LSB bits will match the iode                  []    
00624   unsigned char  *iode,                   //!< 8 bit  issue of data (ephemeris)                                              []
00625   unsigned       *toe,                    //!< reference time ephemeris (0-604800)                                           [s]
00626   unsigned       *toc,                    //!< reference time (clock)   (0-604800)                                           [s]      
00627   unsigned short *week,                   //!< 10 bit gps week 0-1023 (user must account for week rollover )                 [week]    
00628   unsigned char  *health,                 //!< 6 bit health parameter, 0 if healthy, unhealth othersize                      [0=healthy]    
00629   unsigned char  *alert_flag,             //!< 1 = URA may be worse than indicated                                           [0,1]
00630   unsigned char  *anti_spoof,             //!< anti-spoof flag from 0=off, 1=on                                              [0,1]    
00631   unsigned char  *code_on_L2,             //!< 0=reserved, 1=P code on L2, 2=C/A on L2                                       [0,1,2]
00632   unsigned char  *ura,                    //!< User Range Accuracy lookup code, 0 is excellent, 15 is use at own risk        [0-15], see p. 83 GPSICD200C
00633   unsigned char  *L2_P_data_flag,         //!< flag indicating if P is on L2 1=true                                          [0,1]
00634   unsigned char  *fit_interval_flag,      //!< fit interval flag (four hour interval or longer) 0=4 fours, 1=greater         [0,1]
00635   unsigned short *age_of_data_offset,     //!< age of data offset                                                            [s]
00636   double *tgd,     //!< group delay                                                                   [s]
00637   double *af2,     //!< polynomial clock correction coefficient (rate of clock drift)                 [s/s^2]
00638   double *af1,     //!< polynomial clock correction coefficient (clock drift)                         [s/s]
00639   double *af0,     //!< polynomial clock correction coefficient (clock bias)                          [s]    
00640   double *m0,      //!< mean anomaly at reference time                                                [rad]
00641   double *delta_n, //!< mean motion difference from computed value                                    [rad/s]
00642   double *ecc,     //!< eccentricity                                                                  []
00643   double *sqrta,   //!< square root of the semi-major axis                                            [m^(1/2)]
00644   double *omega0,  //!< longitude of ascending node of orbit plane at weekly epoch                    [rad]
00645   double *i0,      //!< inclination angle at reference time                                           [rad]
00646   double *w,       //!< argument of perigee                                                           [rad]
00647   double *omegadot,//!< rate of right ascension                                                       [rad/s]
00648   double *idot,    //!< rate of inclination angle                                                     [rad/s]
00649   double *cuc,     //!< amplitude of the cosine harmonic correction term to the argument of latitude  [rad]
00650   double *cus,     //!< amplitude of the sine harmonic correction term to the argument of latitude    [rad]
00651   double *crc,     //!< amplitude of the cosine harmonic correction term to the orbit radius          [m]
00652   double *crs,     //!< amplitude of the sine harmonic correction term to the orbit radius            [m]
00653   double *cic,     //!< amplitude of the cosine harmonic correction term to the angle of inclination  [rad]
00654   double *cis      //!< amplitude of the sine harmonic correction term to the angle of inclination    [rad]
00655   )
00656 {
00657   unsigned msgLength = 0;
00658   unsigned index = 0; // An index in to the message.
00659   BOOL result = FALSE;
00660 
00661   // Perform sanity checks.
00662   if( message == NULL )
00663   {
00664     GNSS_ERROR_MSG( "if( message == NULL )" );
00665     return FALSE;
00666   }
00667   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x11 ) // sync must be present
00668   {
00669     GNSS_ERROR_MSG( "sync not present" );    
00670     return FALSE;
00671   }
00672 
00673   // Check that the length of the message is correct.
00674   if( messageLength != 108 )
00675   {
00676     GNSS_ERROR_MSG( "if( messageLength != 108 )" );
00677     return FALSE;
00678   }
00679 
00680   // Determine the 4 byte message byte count (includes the header bytes).
00681   index = 8;
00682   msgLength  = message[index];       index++;
00683   msgLength |= message[index] << 8;  index++;
00684   msgLength |= message[index] << 16; index++;
00685   msgLength |= message[index] << 24; index++;
00686 
00687   // Check that the length of the message is correct.
00688   if( messageLength != msgLength )
00689   {
00690     GNSS_ERROR_MSG( "if( messageLength != msgLength )" );
00691     return FALSE;
00692   }  
00693 
00694   index = 12; // after the header
00695   *prn  = message[index];       index++;
00696   *prn |= message[index] << 8;  index++;
00697   *prn |= message[index] << 16; index++;
00698   *prn |= message[index] << 24; index++;
00699   
00700   result = GPS_DecodeRawGPSEphemeris(
00701     &message[index],
00702     &message[index+30],
00703     &message[index+60],    
00704     (unsigned short)(*prn),
00705     tow,
00706     iodc,
00707     iode,  
00708     toe,   
00709     toc,   
00710     week,  
00711     health,
00712     alert_flag,
00713     anti_spoof,
00714     code_on_L2,
00715     ura,       
00716     L2_P_data_flag,
00717     fit_interval_flag,
00718     age_of_data_offset, 
00719     tgd,                
00720     af2,                
00721     af1,                
00722     af0,                
00723     m0,                
00724     delta_n,           
00725     ecc,               
00726     sqrta,             
00727     omega0,            
00728     i0,                
00729     w,                 
00730     omegadot,          
00731     idot,              
00732     cuc,               
00733     cus,               
00734     crc,               
00735     crs,               
00736     cic,               
00737     cis                
00738     );
00739   if( !result )
00740   {
00741     GNSS_ERROR_MSG( "GPS_DecodeRawGPSEphemeris returned FALSE." );    
00742     return FALSE;
00743   }
00744 
00745   return TRUE;
00746 }
00747 
00748 BOOL NOVATELOEM3_DecodeRGEB(
00749   const unsigned char *message,            //!< The message buffer containing a complete RGEB message (input).
00750   const unsigned messageLength,            //!< The length of the entire message (input).
00751   NOVATELOEM3_structObservationHeader* obsHeader, //!< A pointer to a user provided struct with obs header info (output).
00752   NOVATELOEM3_structObservation* obsArray, //!< A pointer to a user provided array of NOVATELOEM3_structObservation (output).
00753   const unsigned char maxNrObs,            //!< The maximum number of elements in the array provided (input).
00754   unsigned *nrObs                          //!< The number of valid elements set in the array (output).
00755   )
00756 {
00757   unsigned nrObsInMessage = 0;
00758   unsigned messageID = 0;
00759   unsigned utmp = 0;
00760   unsigned i = 0;
00761   unsigned j = 0;
00762   unsigned obsIndex = 0;
00763   unsigned char dbytes[8];        // Enough bytes to store a double.
00764   unsigned char fbytes[4];        // Enough bytes to store a float.
00765   double *dptr;                   // A pointer to a double.
00766   float *fptr;                    // A pointer to a float.
00767   
00768   NOVATELOEM3_bitfieldTrackingStatus* ptrTrackStatus = NULL;
00769   NOVATELOEM3_bitfieldSelfTestStatus* ptrSelfStatus = NULL;
00770   
00771   if( message == NULL )
00772   {
00773     GNSS_ERROR_MSG( "if( message == NULL )" );    
00774     return FALSE;
00775   }
00776   if( messageLength < 12+20 ) // message header + rgeb header
00777   {
00778     GNSS_ERROR_MSG( "if( messageLength < 12+20 )" );
00779     return FALSE;
00780   }
00781   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x11 ) // sync must be present
00782   {
00783     GNSS_ERROR_MSG( "sync not present" );    
00784     return FALSE;
00785   }
00786 
00787   if( obsHeader == NULL )
00788   {
00789     GNSS_ERROR_MSG( "if( obsHeader == NULL )" );    
00790     return FALSE;
00791   }
00792   if( obsArray == NULL )
00793   {
00794     GNSS_ERROR_MSG( "if( obsArray == NULL )" );    
00795     return FALSE;
00796   }
00797   if( nrObs == NULL )
00798   {
00799     GNSS_ERROR_MSG( "if( nrObs == NULL )" );    
00800     return FALSE;
00801   }
00802 
00803   memset( obsHeader, 0, sizeof(NOVATELOEM3_structObservationHeader) );
00804   
00805   i = 4; 
00806   messageID  = message[i];       i++;
00807   messageID |= message[i] << 8;  i++;
00808   messageID |= message[i] << 16; i++;
00809   messageID |= message[i] << 24; i++;     
00810 
00811   if( messageID != NOVATELOEM3_RGEB )
00812   {
00813     GNSS_ERROR_MSG( "if( messageID != NOVATELOEM3_RGEB )" );    
00814     return FALSE;
00815   }
00816 
00817   i = 24;
00818   nrObsInMessage  = message[i];       i++;
00819   nrObsInMessage |= message[i] << 8;  i++;
00820   nrObsInMessage |= message[i] << 16; i++;
00821   nrObsInMessage |= message[i] << 24; i++;
00822 
00823   if( nrObsInMessage > maxNrObs )
00824   {
00825     GNSS_ERROR_MSG( "if( nrObsInMessage > maxNrObs )" );    
00826     return FALSE;
00827   }
00828 
00829   obsHeader->nrObs = nrObsInMessage;
00830 
00831   i = 12;
00832   obsHeader->week = message[i];        i++;
00833   obsHeader->week |= message[i] << 8;  i++;
00834   obsHeader->week |= message[i] << 16; i++;
00835   obsHeader->week |= message[i] << 24; i++;
00836 
00837   // Get the time of week.
00838   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
00839   dptr = (double*)&dbytes;
00840   obsHeader->tow = *dptr; 
00841 
00842   // Get the receiver self test status.
00843   i = 28;
00844   utmp = message[i];        i++;
00845   utmp |= message[i] << 8;  i++;
00846   utmp |= message[i] << 16; i++;
00847   utmp |= message[i] << 24; i++;
00848 
00849   ptrSelfStatus = (NOVATELOEM3_bitfieldSelfTestStatus*)&utmp;
00850   obsHeader->status = *ptrSelfStatus;
00851 
00852   for( obsIndex = 0; obsIndex < nrObsInMessage; obsIndex++ )
00853   {
00854     utmp = message[i];        i++;
00855     utmp |= message[i] << 8;  i++;
00856     utmp |= message[i] << 16; i++;
00857     utmp |= message[i] << 24; i++;
00858     
00859     // Get the prn
00860     obsArray[obsIndex].prn = utmp;
00861 
00862     // Get the psr
00863     for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
00864     dptr = (double*)&dbytes;
00865     obsArray[obsIndex].psr = *dptr; 
00866 
00867     // Get the psr std
00868     for( j=0; j<4; j++ ){ fbytes[j] = message[i]; i++; }
00869     fptr = (float*)&fbytes;
00870     obsArray[obsIndex].psrstd = *fptr; 
00871 
00872     // Get the adr
00873     for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
00874     dptr = (double*)&dbytes;
00875     obsArray[obsIndex].adr = *dptr; 
00876 
00877     // Get the adr std
00878     for( j=0; j<4; j++ ){ fbytes[j] = message[i]; i++; }
00879     fptr = (float*)&fbytes;
00880     obsArray[obsIndex].adrstd = *fptr; 
00881 
00882     // Get the Doppler
00883     for( j=0; j<4; j++ ){ fbytes[j] = message[i]; i++; }
00884     fptr = (float*)&fbytes;
00885     obsArray[obsIndex].doppler = *fptr; 
00886 
00887     // Get the CNo
00888     for( j=0; j<4; j++ ){ fbytes[j] = message[i]; i++; }
00889     fptr = (float*)&fbytes;
00890     obsArray[obsIndex].cno = *fptr; 
00891 
00892     // Get the locktime
00893     for( j=0; j<4; j++ ){ fbytes[j] = message[i]; i++; }
00894     fptr = (float*)&fbytes;
00895     obsArray[obsIndex].locktime = *fptr; 
00896 
00897     // Get the tracking status
00898     utmp = message[i];        i++;
00899     utmp |= message[i] << 8;  i++;
00900     utmp |= message[i] << 16; i++;
00901     utmp |= message[i] << 24; i++;
00902 
00903     ptrTrackStatus = (NOVATELOEM3_bitfieldTrackingStatus*)&utmp;
00904     obsArray[obsIndex].status = *ptrTrackStatus;
00905   }
00906 
00907   *nrObs = obsHeader->nrObs;
00908 
00909   return TRUE;
00910 }
00911 
00912 
00913 BOOL NOVATELOEM3_DecodePOSB(
00914   const unsigned char *message,  //!< The message buffer containing a complete RGEB message (input).
00915   const unsigned messageLength,  //!< The length of the entire message (input).
00916   unsigned short* gps_week,      //!< The GPS week number [0-1023], user must account for week rollover (output).
00917   double* gps_tow,               //!< The GPS time of week [0-604800) (output).
00918   double* latitude_degs,         //!< The latitude [deg] (output).
00919   double* longitude_degs,        //!< The longitude [deg] (output).
00920   double* height_msl,            //!< The height (with respect to mean sea level) [m] (output).
00921   double* undulation,            //!< The geoidal undulation [m] (output).
00922   unsigned int* datum_id,        //!< The datum id (61 is WGS84) (output).
00923   double* lat_std,               //!< The estimated solution precision (1-sigma) (output).
00924   double* lon_std,               //!< The estimated solution precision (1-sigma) (output).
00925   double* hgt_std,               //!< The estimated solution precision (1-sigma) (output).
00926   NOVATELOEM3_enumSolutionStatus* status //!< The solution status indicator.
00927   )
00928 {
00929   unsigned messageID = 0;
00930   unsigned utmp = 0;
00931   unsigned i = 0;
00932   unsigned j = 0;
00933   unsigned obsIndex = 0;
00934   unsigned char dbytes[8];        // Enough bytes to store a double.
00935   double *dptr;                   // A pointer to a double.
00936   
00937   if( message == NULL )
00938   {
00939     GNSS_ERROR_MSG( "if( message == NULL )" );    
00940     return FALSE;
00941   }
00942   if( messageLength != 88 ) 
00943   {
00944     GNSS_ERROR_MSG( "if( messageLength != 88 )" );
00945     return FALSE;
00946   }
00947   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x11 ) // sync must be present
00948   {
00949     GNSS_ERROR_MSG( "sync not present" );    
00950     return FALSE;
00951   }
00952 
00953   if( gps_week == NULL ||
00954     gps_tow == NULL ||
00955     latitude_degs == NULL ||
00956     longitude_degs == NULL ||
00957     height_msl == NULL ||
00958     undulation == NULL ||
00959     datum_id == NULL ||
00960     lat_std == NULL ||
00961     lon_std == NULL ||
00962     hgt_std == NULL ||
00963     status == NULL )
00964   {
00965     GNSS_ERROR_MSG( "NULL parameter not allowed." );    
00966     return FALSE;
00967   }
00968 
00969   i = 4; 
00970   messageID  = message[i];       i++;
00971   messageID |= message[i] << 8;  i++;
00972   messageID |= message[i] << 16; i++;
00973   messageID |= message[i] << 24; i++;     
00974 
00975   if( messageID != NOVATELOEM3_POSB )
00976   {
00977     GNSS_ERROR_MSG( "if( messageID != NOVATELOEM3_POSB )" );    
00978     return FALSE;
00979   }
00980 
00981   i = 12;
00982   // Get the week number
00983   utmp  = message[i];       i++;
00984   utmp |= message[i] << 8;  i++;
00985   utmp |= message[i] << 16; i++;
00986   utmp |= message[i] << 24; i++;     
00987    
00988   *gps_week = (unsigned short)utmp;
00989 
00990   // Get the time of week.
00991   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
00992   dptr = (double*)&dbytes;
00993   *gps_tow = *dptr; 
00994 
00995   // Get the latitude.
00996   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
00997   dptr = (double*)&dbytes;
00998   *latitude_degs = *dptr; 
00999 
01000   // Get the longitude.
01001   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01002   dptr = (double*)&dbytes;
01003   *longitude_degs = *dptr; 
01004 
01005   // Get the height.
01006   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01007   dptr = (double*)&dbytes;
01008   *height_msl = *dptr; 
01009 
01010   // Get the undulation.
01011   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01012   dptr = (double*)&dbytes;
01013   *undulation = *dptr; 
01014 
01015   // Get the datum id.
01016   utmp  = message[i];       i++;
01017   utmp |= message[i] << 8;  i++;
01018   utmp |= message[i] << 16; i++;
01019   utmp |= message[i] << 24; i++;     
01020   *datum_id = utmp;
01021 
01022   // Get the latitude std.
01023   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01024   dptr = (double*)&dbytes;
01025   *lat_std = *dptr; 
01026 
01027   // Get the longitude std.
01028   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01029   dptr = (double*)&dbytes;
01030   *lon_std = *dptr; 
01031 
01032   // Get the height std.
01033   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01034   dptr = (double*)&dbytes;
01035   *hgt_std = *dptr; 
01036 
01037   // Get the solution status.
01038   utmp  = message[i];       i++;
01039   utmp |= message[i] << 8;  i++;
01040   utmp |= message[i] << 16; i++;
01041   utmp |= message[i] << 24; i++;    
01042   *status = (NOVATELOEM3_enumSolutionStatus)utmp;
01043 
01044   return TRUE;
01045 }
01046 
01047 
01048 BOOL NOVATELOEM3_DecodeTM1B(
01049   const unsigned char *message,  //!< The message buffer containing a complete RGEB message (input).
01050   const unsigned messageLength,  //!< The length of the entire message (input).
01051   unsigned short* gps_week,      //!< The GPS week number [0-1023], user must account for week rollover (output).
01052   double* gps_tow,               //!< The GPS time of week [0-604800) (output).
01053   double* clk_offset,            //!< The receiver clock offset [s] (output). GPSTime = receiver_time - offset.
01054   double* clk_offset_std,        //!< The estimated precision of the clock offset [s] at 1 sigma (output).
01055   double* utc_offset,            //!< The estimated difference between UTC and GPS time. UTC_time = GPS_time + utc_offset. (e.g. -13.0) (output).
01056   BOOL* is_clk_stabilized        //!< A boolean to indicate if the clock is stable (output).
01057   )
01058 {
01059   unsigned messageID = 0;
01060   unsigned utmp = 0;
01061   unsigned i = 0;
01062   unsigned j = 0;
01063   unsigned obsIndex = 0;
01064   unsigned char dbytes[8];        // Enough bytes to store a double.
01065   double *dptr;                   // A pointer to a double.
01066   
01067   if( message == NULL )
01068   {
01069     GNSS_ERROR_MSG( "if( message == NULL )" );    
01070     return FALSE;
01071   }
01072   if( messageLength != 52 ) 
01073   {
01074     GNSS_ERROR_MSG( "if( messageLength != 52 )" );
01075     return FALSE;
01076   }
01077   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x11 ) // sync must be present
01078   {
01079     GNSS_ERROR_MSG( "sync not present" );    
01080     return FALSE;
01081   }
01082 
01083   if( gps_week == NULL ||
01084     gps_tow == NULL ||
01085     clk_offset == NULL ||
01086     clk_offset_std == NULL ||
01087     utc_offset == NULL ||
01088     is_clk_stabilized == NULL ) 
01089   {
01090     GNSS_ERROR_MSG( "NULL parameter not allowed." );    
01091     return FALSE;
01092   }
01093 
01094   i = 4; 
01095   messageID  = message[i];       i++;
01096   messageID |= message[i] << 8;  i++;
01097   messageID |= message[i] << 16; i++;
01098   messageID |= message[i] << 24; i++;     
01099 
01100   if( messageID != NOVATELOEM3_TM1B )
01101   {
01102     GNSS_ERROR_MSG( "if( messageID != NOVATELOEM3_TM1B )" );    
01103     return FALSE;
01104   }
01105 
01106   i = 12;
01107   // Get the week number
01108   utmp  = message[i];       i++;
01109   utmp |= message[i] << 8;  i++;
01110   utmp |= message[i] << 16; i++;
01111   utmp |= message[i] << 24; i++;     
01112    
01113   *gps_week = (unsigned short)utmp;
01114 
01115   // Get the time of week.
01116   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01117   dptr = (double*)&dbytes;
01118   *gps_tow = *dptr; 
01119 
01120   // Get the clock offset.
01121   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01122   dptr = (double*)&dbytes;
01123   *clk_offset = *dptr; 
01124 
01125   // Get the clock offset std.
01126   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01127   dptr = (double*)&dbytes;
01128   *clk_offset_std = *dptr; 
01129 
01130   // Get the utc offset.
01131   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01132   dptr = (double*)&dbytes;
01133   *utc_offset = *dptr; 
01134 
01135   // Get the clock status.
01136   utmp  = message[i];       i++;
01137   utmp |= message[i] << 8;  i++;
01138   utmp |= message[i] << 16; i++;
01139   utmp |= message[i] << 24; i++;     
01140 
01141   if( utmp == 0 )
01142   {
01143     *is_clk_stabilized = TRUE;
01144   }
01145   else
01146   {
01147     *is_clk_stabilized = FALSE;
01148   }
01149 
01150   return TRUE;
01151 }
01152 
01153 
01154 
01155 BOOL NOVATELOEM3_DecodeIONB(
01156   const unsigned char *message, //!< The message buffer containing a complete RGEB message (input).
01157   const unsigned messageLength, //!< The length of the entire message (input).
01158   double *alpha0,     //!< coefficients of a cubic equation representing the amplitude of the vertical delay [s] (output).
01159   double *alpha1,     //!< coefficients of a cubic equation representing the amplitude of the vertical delay [s/semi-circle] (output).
01160   double *alpha2,     //!< coefficients of a cubic equation representing the amplitude of the vertical delay [s/semi-circle^2] (output).
01161   double *alpha3,     //!< coefficients of a cubic equation representing the amplitude of the vertical delay [s/semi-circle^3] (output).
01162   double *beta0,      //!< coefficients of a cubic equation representing the period of the model [s] (output).
01163   double *beta1,      //!< coefficients of a cubic equation representing the period of the model [s/semi-circle] (output).
01164   double *beta2,      //!< coefficients of a cubic equation representing the period of the model [s/semi-circle^2] (output).
01165   double *beta3       //!< coefficients of a cubic equation representing the period of the model [s/semi-circle^3] (output).
01166   )
01167 {
01168   unsigned messageID = 0;
01169   unsigned i = 0;
01170   unsigned j = 0;
01171   unsigned char dbytes[8]; // Enough bytes to store a double.
01172   double *dptr = NULL;     // A pointer to a double.
01173 
01174   if( message == NULL )
01175   {
01176     GNSS_ERROR_MSG( "if( message == NULL )");
01177     return FALSE;
01178   }
01179   if( messageLength != 76 )
01180   {
01181     GNSS_ERROR_MSG( "if( messageLength != 76 )");
01182     return FALSE;
01183   }
01184 
01185   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x11 ) // sync must be present
01186   {
01187     GNSS_ERROR_MSG( "sync not present" );    
01188     return FALSE;
01189   }
01190   if( alpha0 == NULL ||
01191       alpha1 == NULL || 
01192       alpha2 == NULL || 
01193       alpha3 == NULL || 
01194       beta0  == NULL || 
01195       beta1  == NULL || 
01196       beta2  == NULL ||
01197       beta3  == NULL )      
01198   {
01199     GNSS_ERROR_MSG( "NULL alpha or beta parameters.");
01200     return FALSE;
01201   }
01202   
01203   i = 4; 
01204   messageID  = message[i];       i++;
01205   messageID |= message[i] << 8;  i++;
01206   messageID |= message[i] << 16; i++;
01207   messageID |= message[i] << 24; i++;     
01208 
01209   if( messageID != NOVATELOEM3_IONB )
01210   {
01211     GNSS_ERROR_MSG( "if( messageID != NOVATELOEM3_IONB )");
01212     return FALSE;
01213   }
01214 
01215   i = 12;  
01216   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01217   dptr = (double*)&dbytes;
01218   *alpha0 = *dptr;
01219 
01220   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01221   dptr = (double*)&dbytes;
01222   *alpha1 = *dptr;
01223 
01224   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01225   dptr = (double*)&dbytes;
01226   *alpha2 = *dptr;
01227 
01228   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01229   dptr = (double*)&dbytes;
01230   *alpha3 = *dptr;
01231 
01232   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01233   dptr = (double*)&dbytes;
01234   *beta0 = *dptr;
01235 
01236   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01237   dptr = (double*)&dbytes;
01238   *beta1 = *dptr;
01239   
01240   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01241   dptr = (double*)&dbytes;
01242   *beta2 = *dptr;
01243 
01244   for( j=0; j<8; j++ ){ dbytes[j] = message[i]; i++; }
01245   dptr = (double*)&dbytes;
01246   *beta3 = *dptr;
01247 
01248   return TRUE;
01249 }
01250 
01251 
01252 
01253 BOOL NOVATELOEM4_FindNextMessageInFile(
01254   FILE *fid,                       //!< A file pointer to an open file (input).
01255   unsigned char *message,          //!< A message buffer in which to place the message found (input/output).
01256   const unsigned maxMessageLength, //!< The maximum size of the message buffer (input).
01257   BOOL *wasEndOfFileReached,       //!< Has the end of the file been reached (output).
01258   BOOL *wasMessageFound,           //!< Was a valid message found (output).
01259   unsigned *filePosition,          //!< The file position for the start of the message found (output).
01260   unsigned short *messageLength,   //!< The length of the entire message found and stored in the message buffer (output).
01261   unsigned short *messageID,       //!< The message ID of the message found.
01262   unsigned *numberBadCRC           //!< The number of bad crc values found. (crc fails or mistaken messages).  
01263   )
01264 {
01265   unsigned i = 0;                  // The index into the message buffer.
01266   unsigned char sync[3];           // 0xAA 0x44 0x12
01267   unsigned char headerLength = 0;  // The length of the message header [bytes].
01268   unsigned byteCount = 0;          // This indicates the number of bytes read by fread().
01269   unsigned short dataLength = 0;   // The length of the data portion of the message. i.e. *messageLength - headerLength - CRCLength.
01270   unsigned short msgLength = 0;    // The entire length of the current message being examined.
01271   int fpos = 0;                    // A signed file position (needs sign for error checking).
01272   unsigned messageCRC = 0;         // The message CRC value.
01273   BOOL startSearch = TRUE;         // A boolean to indicate that the sync search is occurring.
01274   BOOL isCRCValid = FALSE;         // A boolean to indicate if the CRC is valid. Does it match the calculated value.
01275 
01276 
01277   // Initialize the output parameters.
01278   *wasEndOfFileReached = FALSE;
01279   *wasMessageFound = 0;
01280   *filePosition    = 0;
01281   *messageLength   = 0;
01282   *messageID       = 0;
01283   *numberBadCRC    = 0;
01284   
01285   // Ensure that the file pointer is valid.
01286   if( fid == NULL )
01287   {
01288     GNSS_ERROR_MSG( "if( fid == NULL )" );
01289     return FALSE;
01290   }
01291 
01292   // Ensure that the maximum message length is appropriate.
01293   if( maxMessageLength < 32 ) // at least 3 sync bytes plus 25 header bytes plus the 4 byte CRC.
01294   {
01295     GNSS_ERROR_MSG( "if( maxMessageLength < 32 )" );
01296     return FALSE;
01297   }
01298   
01299   // Ensure that the file pointer is not at the end of the file.
01300   if( feof(fid) )
01301   {
01302     *wasEndOfFileReached = TRUE;
01303     return TRUE;
01304   }
01305   
01306   while( !(*wasEndOfFileReached) && !(*wasMessageFound) )
01307   {
01308     if( startSearch )
01309     {
01310       // Get the first two sync bytes.
01311       sync[0] = (unsigned char)fgetc( fid );
01312       if( feof( fid ) )
01313       {
01314         *wasEndOfFileReached = TRUE;
01315         return TRUE;
01316       }
01317 
01318       sync[1] = (unsigned char)fgetc( fid );
01319       if( feof( fid ) )
01320       {
01321         *wasEndOfFileReached = TRUE;
01322         return TRUE;
01323       }  
01324 
01325       startSearch = FALSE;
01326     }
01327 
01328     // Get the last sync byte.
01329     sync[2] = (unsigned char)fgetc( fid );
01330     if( feof( fid ) )
01331     {
01332       *wasEndOfFileReached = TRUE;
01333       return TRUE;
01334     }
01335 
01336     // Check the full sync.
01337     if( sync[0] == 0xAA && sync[1] == 0x44 && sync[2] == 0x12 )
01338     {
01339       // Found a potential message.
01340       i = 0;
01341       message[i] = sync[0]; i++;
01342       message[i] = sync[1]; i++;
01343       message[i] = sync[2]; i++;
01344 
01345       // Determine the file position of the start of the message
01346       fpos = ftell(fid);
01347       if( fpos < 2 ) // check less than 2 because we are at least 3 bytes into the file
01348       {
01349         GNSS_ERROR_MSG( "if( fpos < 2 )" );
01350         return FALSE;
01351       }
01352       *filePosition = fpos - 3; // The start of the message sync.
01353 
01354       // Get the header length.
01355       headerLength = (unsigned char)fgetc( fid );
01356       if( feof( fid ) )
01357       {
01358         *wasEndOfFileReached = TRUE;
01359         return TRUE;
01360       }
01361       message[i] = headerLength;
01362       i++;
01363 
01364       // Get rest of the header (maximum of 255 bytes).
01365       byteCount = (int)fread( &(message[i]), sizeof(unsigned char), headerLength-4, fid );
01366       if( byteCount+4 != headerLength )
01367       {
01368         *wasEndOfFileReached = TRUE;
01369         return TRUE;
01370       }
01371 
01372       // Determine the 2 byte message ID.
01373       *messageID  = message[i]; 
01374       i++;
01375       *messageID |= message[i] << 8;      
01376       i++;
01377 
01378       // Skip the message type and the port address.
01379       i += 2;
01380 
01381       // Determine the 2 byte data length.
01382       dataLength = message[i];
01383       i++;
01384       dataLength |= message[i] << 8;
01385       i++;
01386 
01387       // Check that the entire message length will fit in the message buffer.
01388       msgLength = headerLength + dataLength + 4; // plus 4 for the CRC.
01389       if( msgLength > maxMessageLength )
01390       {
01391         // Perhaps the data length was bad.
01392         // Start searching again after the sync that was found.
01393         // Set the file position to the last of the three sync bytes.
01394         if( fseek( fid, fpos, SEEK_SET ) != 0 )
01395         {
01396           // The seek failed.
01397           GNSS_ERROR_MSG( "fseek failed." );            
01398           return FALSE;
01399         }
01400         startSearch = TRUE;
01401         continue;
01402       }
01403 
01404       // Get the data part of the message.
01405       // advance i to the start of the data
01406       i = headerLength;
01407       byteCount = (int)fread( &(message[i]), sizeof(unsigned char), dataLength, fid );
01408       if( byteCount != dataLength )
01409       {
01410         // Either a message has an invalid length or a message was cut off.
01411         // We do not want to read over any valid message so start the search again.
01412         // Start searching again after the sync that was found.
01413         // Set the file position to the last of the three sync bytes.
01414         if( fseek( fid, fpos, SEEK_SET ) != 0 )
01415         {
01416           // The seek failed.
01417           GNSS_ERROR_MSG( "fseek failed." );
01418           return FALSE;
01419         }
01420         startSearch = TRUE;
01421         continue;
01422       }
01423       i += dataLength;
01424 
01425       // Get the CRC.
01426       byteCount = (int)fread( &(message[i]), sizeof(unsigned char), 4, fid );
01427       if( byteCount != 4 )
01428       {
01429         *wasEndOfFileReached = TRUE;
01430         return TRUE;
01431       }
01432       messageCRC  = message[i];
01433       i++;
01434       messageCRC |= message[i] << 8;
01435       i++;
01436       messageCRC |= message[i] << 16;
01437       i++;
01438       messageCRC |= message[i] << 24;
01439       i++;
01440       
01441       // Compare the received message CRC with the calculated CRC.
01442       if( !NOVATEL_CheckCRC32( message, msgLength, messageCRC, &isCRCValid ) )
01443       {
01444         GNSS_ERROR_MSG( "NOVATEL_CheckCRC32 returned FALSE." );
01445         return FALSE;
01446       }
01447       if( !isCRCValid )
01448       {
01449         *numberBadCRC += 1;
01450 
01451         // Start searching again after the sync that was found.
01452         // Set the file position to the last of the three sync bytes.
01453         if( fseek( fid, fpos, SEEK_SET ) != 0 )
01454         {
01455           // The seek failed.
01456           GNSS_ERROR_MSG( "fseek failed." );          
01457           return FALSE;
01458         }
01459         startSearch = TRUE;
01460         continue;
01461       }
01462 
01463       *wasMessageFound = TRUE;
01464       *messageLength = msgLength;
01465       break;
01466     }
01467     else
01468     {
01469       // Shift the first two bytes of the sync.
01470       sync[0] = sync[1];
01471       sync[1] = sync[2];
01472     }
01473   }
01474   return TRUE;
01475 }
01476 
01477 
01478 
01479 BOOL NOVATELOEM4_FindNextMessageInBuffer(
01480   unsigned char *buffer,           //!< A pointer to a buffer containing input data.
01481   const unsigned bufferLength,     //!< The length of the valid data contained in the buffer.
01482   unsigned char *message,          //!< A message buffer in which to place the message found (input/output).
01483   const unsigned maxMessageLength, //!< The maximum size of the message buffer (input).
01484   BOOL *wasEndOfBufferReached,     //!< Has the end of the buffer been reached (output).
01485   BOOL *wasMessageFound,           //!< Was a valid message found (output).
01486   unsigned *startPosition,         //!< The index into the buffer for the start of the message found (output).
01487   unsigned short *messageLength,   //!< The length of the entire message found and stored in the message buffer (output).
01488   unsigned short *messageID,       //!< The message ID of the message found.
01489   unsigned *numberBadCRC           //!< The number of bad crc values found. (crc fails or mistaken messages).  
01490   )
01491 {
01492   unsigned bi = 0;                 // The index into the input buffer.
01493   unsigned i = 0;                  // The index into the message buffer.
01494   unsigned char sync[3];           // 0xAA 0x44 0x11
01495   unsigned dataLength = 0;         // The length of the data portion of the message. i.e. Entire message length - 12.
01496   unsigned msgLength = 0;          // The entire length of the current message being examined.
01497   int bpos = 0;                    // An index into the buffer (needs sign for error checking).
01498   unsigned messageCRC = 0;         // The message CRC value.
01499   BOOL startSearch = TRUE;         // A boolean to indicate that the sync search is occurring.
01500   BOOL isCRCValid = FALSE;         // A boolean to indicate if the CRC is valid. Does it match the calculated value.
01501   unsigned char headerLength = 0;  // The length of the message header [bytes].
01502   
01503   // Initialize the output parameters.
01504   *wasEndOfBufferReached = FALSE;
01505   *wasMessageFound     = 0;
01506   *startPosition       = 0;
01507   *messageLength       = 0;
01508   *messageID           = 0;
01509   *numberBadCRC        = 0;
01510 
01511   // Ensure that the buffer pointer is valid.
01512   if( buffer == NULL )
01513   {
01514     GNSS_ERROR_MSG( "if( fid == NULL )" );
01515     return FALSE;
01516   }
01517   if( message == NULL )
01518   {
01519     GNSS_ERROR_MSG( "if( message == NULL )" );
01520     return FALSE;
01521   }
01522 
01523   // Ensure that the maximum message length is appropriate.
01524   if( maxMessageLength < 32 ) // at least 3 sync bytes plus 25 header bytes plus the 4 byte CRC.
01525   {
01526     GNSS_ERROR_MSG( "if( maxMessageLength < 32 )" );
01527     return FALSE;
01528   }  
01529   
01530   while( !(*wasEndOfBufferReached) && !(*wasMessageFound) )
01531   {
01532     if( startSearch )
01533     {
01534       // Get the first two sync bytes.
01535       sync[0] = buffer[bi]; bi++;
01536       if( bi >= bufferLength )
01537       {
01538         *wasEndOfBufferReached = TRUE;
01539         return TRUE;
01540       }
01541 
01542       sync[1] = buffer[bi]; bi++;
01543       if( bi >= bufferLength )
01544       {
01545         *wasEndOfBufferReached = TRUE;
01546         return TRUE;
01547       }  
01548       startSearch = FALSE;
01549     }
01550 
01551     // Get the last sync byte.
01552     sync[2] = buffer[bi]; bi++;
01553     if( bi >= bufferLength )
01554     {
01555       *wasEndOfBufferReached = TRUE;
01556       return TRUE;
01557     }
01558 
01559     // Check the full sync.
01560     if( sync[0] == 0xAA && sync[1] == 0x44 && sync[2] == 0x12 )
01561     {
01562       // Found a potential message.
01563       i = 0;
01564       message[i] = sync[0]; i++;
01565       message[i] = sync[1]; i++;
01566       message[i] = sync[2]; i++;
01567 
01568       // Determine the file position of the start of the message
01569       bpos = bi;
01570       *startPosition = bi - 3; // The start of the message sync.
01571 
01572       
01573       // Get the header length.
01574       headerLength = buffer[bi]; bi++;
01575       if( bi > bufferLength )
01576       {
01577         *wasEndOfBufferReached = TRUE;
01578         return TRUE;
01579       }
01580       message[i] = headerLength;
01581       i++;
01582 
01583       // Get rest of the header (maximum of 255 bytes).
01584       if( bi+headerLength-4 > bufferLength )
01585       {
01586         *wasEndOfBufferReached = TRUE;
01587         return TRUE;
01588       }
01589       memcpy( &(message[i]), (buffer+bi), (headerLength-4) );
01590       bi += headerLength-4;
01591 
01592       // Determine the 2 byte message ID.
01593       *messageID  = message[i]; 
01594       i++;
01595       *messageID |= message[i] << 8;      
01596       i++;
01597 
01598       // Skip the message type and the port address.
01599       i += 2;
01600 
01601       // Determine the 2 byte data length.
01602       dataLength = message[i];
01603       i++;
01604       dataLength |= message[i] << 8;
01605       i++;
01606 
01607       // Check that the entire message length will fit in the message buffer.
01608       msgLength = headerLength + dataLength + 4; // plus 4 for the CRC.
01609       if( msgLength > maxMessageLength )
01610       {
01611         // Perhaps the data length was bad.
01612         // Start searching again after the sync that was found.
01613         // Set the buffer index to the last of the three sync bytes.
01614         bi = bpos;        
01615         startSearch = TRUE;
01616         continue;
01617       }
01618 
01619       // Get the data part of the message.
01620       // advance i to the start of the data
01621       i = headerLength;
01622       if( bi+dataLength > bufferLength )
01623       {
01624         // if all of the message is not yet in the buffer this will occur.
01625         *wasEndOfBufferReached = TRUE;
01626         return TRUE;
01627       }
01628       memcpy( &(message[i]), (buffer+bi), dataLength );
01629       bi += dataLength;      
01630       i += dataLength;
01631 
01632       // Get the CRC.
01633       if( bi + 4 > bufferLength )
01634       {
01635         // if all of the message is not yet in the buffer this will occur.
01636         *wasEndOfBufferReached = TRUE;
01637         return TRUE;
01638       }
01639       message[i] = buffer[bi]; i++; bi++;
01640       message[i] = buffer[bi]; i++; bi++;
01641       message[i] = buffer[bi]; i++; bi++;
01642       message[i] = buffer[bi]; i++; bi++;
01643 
01644       i -= 4;
01645       messageCRC  = message[i];       i++;
01646       messageCRC |= message[i] << 8;  i++;
01647       messageCRC |= message[i] << 16; i++;
01648       messageCRC |= message[i] << 24; i++;
01649 
01650       // Compare the received message CRC with the calculated CRC.
01651       if( !NOVATEL_CheckCRC32( message, msgLength, messageCRC, &isCRCValid ) )
01652       {
01653         GNSS_ERROR_MSG( "NOVATEL_CheckCRC32 returned FALSE." );
01654         return FALSE;
01655       }
01656       if( !isCRCValid )
01657       {
01658         *numberBadCRC += 1;
01659         
01660         // Start searching again after the sync that was found.
01661         // Set the file position to the last of the three sync bytes.
01662         bi = bpos;
01663         startSearch = TRUE;
01664         continue;
01665       }
01666 
01667       *wasMessageFound = TRUE;
01668       *messageLength = msgLength;
01669       break;
01670     }
01671     else
01672     {
01673       // Shift the first two bytes of the sync.
01674       sync[0] = sync[1];
01675       sync[1] = sync[2];
01676     }
01677   }
01678   return TRUE;
01679 }
01680 
01681 
01682 
01683 BOOL NOVATELOEM4_DecodeBinaryMessageHeader(
01684   const unsigned char *message,            //!< The message buffer containing a complete NOVATEL OEM4 binary message (input).
01685   const unsigned short messageLength,      //!< The length of the entire message (input).
01686   NOVATELOEM4_structBinaryHeader *header   //!< A pointer to a NovAtel OEM4 header information struct (output).
01687   )
01688 {
01689   unsigned u32 = 0;
01690   NOVATELOEM4_structRxStatusBitField* ptrRxStatusBitField = NULL;
01691 
01692   // sanity checks
01693   if( message == NULL )
01694   {
01695     GNSS_ERROR_MSG( "if( message == NULL )" );
01696     return FALSE;
01697   }
01698   if( header == NULL )
01699   {
01700     GNSS_ERROR_MSG( "if( header == NULL )" );
01701     return FALSE;
01702   }
01703 
01704   if( messageLength < 4 ) // at least the sync bytes and the header length
01705   {
01706     GNSS_ERROR_MSG( "if( messageLength < 4 )" );
01707     return FALSE;
01708   }
01709   
01710   // Get the header length;
01711   header->headerLength = message[3];
01712   if( messageLength < header->headerLength )
01713   {
01714     GNSS_ERROR_MSG( "if( messageLength < header->headerLength )" );
01715     return FALSE;
01716   }
01717   
01718   header->messageID  = message[4];
01719   header->messageID |= message[5] << 8;
01720 
01721   header->messageType = message[6];
01722 
01723   header->portAddress = message[7];
01724   
01725   header->dataLength  = message[8];
01726   header->dataLength |= message[9] << 8;
01727 
01728   header->sequenceNr  = message[10];
01729   header->sequenceNr |= message[11] << 8;
01730 
01731   header->idleTime = message[12];
01732   
01733   header->eTimeStatus = (NOVATELOEM4_enumTimeStatus)message[13];
01734 
01735   header->gpsWeek  = message[14];
01736   header->gpsWeek |= message[15] << 8;
01737 
01738   header->gpsMilliSeconds  = message[16];
01739   header->gpsMilliSeconds |= message[17] << 8;
01740   header->gpsMilliSeconds |= message[18] << 16;
01741   header->gpsMilliSeconds |= message[19] << 24;
01742 
01743   u32  = message[20];
01744   u32 |= message[21] << 8;
01745   u32 |= message[22] << 16;
01746   u32 |= message[23] << 24;
01747   ptrRxStatusBitField = (NOVATELOEM4_structRxStatusBitField *)&u32;  
01748   header->receiverStatus = *ptrRxStatusBitField;
01749 
01750   header->reserved  = message[24];
01751   header->reserved |= message[25] << 8;
01752 
01753   header->receiverVersion  = message[26];
01754   header->receiverVersion |= message[27] << 8;
01755 
01756   return TRUE;
01757 }
01758 
01759 
01760 BOOL NOVATELOEM4_DecodeRANGECMPB(
01761   const unsigned char *message,            //!< The message buffer containing a complete RANGEB message (input).
01762   const unsigned short messageLength,      //!< The length of the entire message (input).
01763   NOVATELOEM4_structBinaryHeader* header,  //!< A pointer to a NovAtel OEM4 header information struct (output).
01764   NOVATELOEM4_structObservation* obsArray, //!< A pointer to a user provided array of struct_NOVATELOEM4_RANGE (output).
01765   const unsigned char maxNrObs,            //!< The maximum number of elements in the array provided (input).
01766   unsigned *nrObs                          //!< The number of valid elements set in the array (output).
01767   )
01768 {
01769   unsigned i = 0;                 // A counter.
01770   unsigned index = 0;             // An index into the message buffer.
01771   unsigned char headerLength = 0; // The length of the header only as indicated in the header.
01772   unsigned short dataLength = 0;  // The length of the data part of the message as indicated in the header.
01773   unsigned short msgLength = 0;   // The computed length of the entire message.
01774   unsigned short testLength = 0;  // The expected length of the data given the number of observations.
01775   
01776   // Perform sanity checks.
01777   if( message == NULL )
01778   {
01779     GNSS_ERROR_MSG( "if( message == NULL )" );
01780     return FALSE;
01781   }
01782   if( obsArray == NULL )
01783   {
01784     GNSS_ERROR_MSG( "if( obsArray == NULL )" );
01785     return FALSE;
01786   }
01787   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x12 ) // sync must be present
01788   {
01789     GNSS_ERROR_MSG( "sync is not present" );
01790     return FALSE;
01791   }
01792 
01793   // Decode the binary header.
01794   if( !NOVATELOEM4_DecodeBinaryMessageHeader( message, messageLength, header ) )
01795   {
01796     GNSS_ERROR_MSG( "NOVATELOEM4_DecodeBinaryMessageHeader returned FALSE." );
01797     return FALSE;
01798   }
01799 
01800   // Get the header length.
01801   headerLength = message[3];
01802 
01803   // Get the data length.
01804   dataLength = message[8];
01805   dataLength |= message[9] << 8;
01806 
01807   // Check that the data length + header length + 4 (crc) == messageLength provided.
01808   msgLength = dataLength + headerLength + 4;
01809   if( msgLength != messageLength )
01810   {
01811     GNSS_ERROR_MSG( "if( msgLength != messageLength )" );
01812     return FALSE;
01813   }
01814 
01815   // Get the number of observations.
01816   index = headerLength;
01817   *nrObs = message[index]; 
01818   index++;
01819   *nrObs |= message[index] << 8;
01820   index++;
01821   *nrObs |= message[index] << 16;
01822   index++;
01823   *nrObs |= message[index] << 24;
01824 
01825   // Check that there is enough room in the array provided.
01826   if( maxNrObs < *nrObs )
01827   {
01828     GNSS_ERROR_MSG( "if( maxNrObs < *nrObs )" );
01829     return FALSE;
01830   }
01831 
01832   // Check that the number of observations fits the data length given.
01833   testLength = (unsigned short)(*nrObs*24 + 4);
01834   if( testLength != dataLength )
01835   {
01836     GNSS_ERROR_MSG( "if( testLength != dataLength )" );
01837     return FALSE;
01838   }
01839 
01840   // Decode the data.
01841   index = headerLength+4;
01842   for( i = 0; i < *nrObs; i++ )
01843   {
01844     long long int rangecmp_psr       = 0;  // Pseudorange
01845     long rangecmp_adr                = 0;  // Carrier Phase
01846     double adr_rolls                 = 0;  // ADR Roll Over
01847     long rangecmp_doppler_freq       = 0;  // Doppler Frequency 
01848     unsigned char rangecmp_stdev_psr = 0;  // Standard Deviation of Pseudorange
01849     unsigned char rangecmp_stdev_adr = 0;  // Standard Deviation of Carrier Phase
01850     unsigned long rangecmp_lock_time = 0;  // Lock Time
01851     unsigned long rangecmp_cno       = 0;  // Carier to Noise Density
01852     double dtmp = 0;
01853 
01854     // Tracking Status  (32 bits 0 - 31)   
01855     obsArray[i].rawTrackingStatus  = message[index];       index++;
01856     obsArray[i].rawTrackingStatus |= message[index] <<  8; index++;
01857     obsArray[i].rawTrackingStatus |= message[index] << 16; index++;
01858     obsArray[i].rawTrackingStatus |= message[index] << 24; index++;
01859 
01860     if( !NOVATELOEM4_DecodeTrackingStatus( obsArray[i].rawTrackingStatus, &obsArray[i].trackingStatus ) )    
01861     {
01862       GNSS_ERROR_MSG( "NOVATELOEM4_DecodeTrackingStatus returned FALSE." );
01863       return FALSE;    
01864     }
01865   
01866     // Doppler Frequency (28 bits 32-59)
01867     rangecmp_doppler_freq |=  message[index];        index++;
01868     rangecmp_doppler_freq |=  message[index] << 8;   index++;
01869     rangecmp_doppler_freq |=  message[index] << 16;  index++;
01870     rangecmp_doppler_freq |= (message[index] & 0x0F) << 24;  
01871     // check negative value.
01872     if( (rangecmp_doppler_freq >> 27) > 0 )
01873     {    
01874       rangecmp_doppler_freq |= 0xF0000000;      
01875     }
01876     dtmp = (double)(rangecmp_doppler_freq);
01877     dtmp /= 256.0;
01878     obsArray[i].doppler = (float)dtmp;
01879 
01880     // Pseudorange (36 bits 60-95)
01881     rangecmp_psr    |= (message[index]&0xF0)>>4; index++;
01882     rangecmp_psr    |=  message[index]<<4;       index++;
01883     rangecmp_psr    |=  message[index]<<12;      index++;
01884     rangecmp_psr    |=  message[index]<<20;      index++;
01885     rangecmp_psr    |= (long long int)(message[index])<<28; index++;    
01886     // check negative value.
01887     if( ((long long int)(rangecmp_psr)>>35) > 0 )
01888     {
01889       // The checkneg variable was added to avoid compiler warnings with g++ (v4.1.2).
01890       unsigned long int checkneg = 0xFFFFFFF0;
01891       checkneg *= (unsigned long int)(1<<31);
01892       checkneg *= 2; // this is 0xFFFF FFF0 0000 0000
01893       rangecmp_psr |= checkneg;
01894     }
01895     obsArray[i].psr  = (double)rangecmp_psr;
01896     obsArray[i].psr /= 128.0; 
01897 
01898     // Carrier Phase (32 bits 96-127)
01899     rangecmp_adr   = message[index];       index++;
01900     rangecmp_adr  |= message[index] << 8;  index++;
01901     rangecmp_adr  |= message[index] << 16; index++;
01902     rangecmp_adr  |= message[index] << 24; index++;
01903     obsArray[i].adr  = (double) rangecmp_adr;
01904     obsArray[i].adr /= 256.0; 
01905 
01906     // Carrier Phase Roll over Calculations
01907     if (obsArray[i].trackingStatus.eFrequency == NOVATELOEM4_L1)
01908       adr_rolls =(obsArray[i].psr / GPS_WAVELENGTHL1  + obsArray[i].adr) / 8388608.0;
01909     else
01910       adr_rolls =(obsArray[i].psr / GPS_WAVELENGTHL2  + obsArray[i].adr) / 8388608.0;
01911 
01912     if ( adr_rolls <= 0)
01913       adr_rolls = adr_rolls - 0.5;
01914     else
01915       adr_rolls = adr_rolls + 0.5;
01916 
01917     obsArray[i].adr = obsArray[i].adr  - (8388608.0 * (int)adr_rolls);
01918 
01919     // Pseudorange Standard Deviation (4 bits 128-131)
01920     rangecmp_stdev_psr = ((message[index] & 0x0F)); 
01921 
01922     // Refer to page 352 OEMV Family Firmware Version 3.100 Reference Manual Rev 3
01923     // Refer to page 143 OEM4 Family Firmware Version 1.000 Command and Log Reference Manual Rev 4
01924     switch(rangecmp_stdev_psr)
01925     { 
01926     case 0  : obsArray[i].psrstd = 0.050f; break;
01927     case 1  : obsArray[i].psrstd = 0.075f; break;
01928     case 2  : obsArray[i].psrstd = 0.113f; break;
01929     case 3  : obsArray[i].psrstd = 0.169f; break;
01930     case 4  : obsArray[i].psrstd = 0.253f; break;
01931     case 5  : obsArray[i].psrstd = 0.380f; break;
01932     case 6  : obsArray[i].psrstd = 0.570f; break;
01933     case 7  : obsArray[i].psrstd = 0.854f; break;
01934     case 8  : obsArray[i].psrstd = 1.281f; break;
01935     case 9  : obsArray[i].psrstd = 2.375f; break;
01936     case 10 : obsArray[i].psrstd = 4.750f; break;
01937     case 11 : obsArray[i].psrstd = 9.500f; break;
01938     case 12 : obsArray[i].psrstd = 19.000f; break;
01939     case 13 : obsArray[i].psrstd = 38.000f; break;
01940     case 14 : obsArray[i].psrstd = 76.000f; break;
01941     case 15 : obsArray[i].psrstd = 152.000f; break;
01942     };
01943 
01944     // Carrier Phase Standard Deviation (4 bits 132-135)
01945     rangecmp_stdev_adr =  message[index] >> 4 ; 
01946     index++;
01947     obsArray[i].adrstd = (float)(rangecmp_stdev_adr+1)/512;
01948 
01949     // Prn Number (8 bits 136-143)
01950     obsArray[i].prn = (unsigned short)message[index]; 
01951     index++;
01952 
01953     // Lock Time  (21 bits 144-164)
01954     rangecmp_lock_time   |= message[index];      index++;
01955     rangecmp_lock_time   |= message[index] << 8; index++;
01956     rangecmp_lock_time   |= ((message[index] & 0x1F)) << 16;  
01957 
01958     obsArray[i].locktime  = (float)(rangecmp_lock_time);
01959     obsArray[i].locktime /= 32.0;
01960 
01961     // Carrier to Noise Density ( 5 bits 165-169)
01962     rangecmp_cno         = (message[index] & 0xE0 ) >> 5; index++;  
01963     rangecmp_cno        |= (message[index] & 0x03 ) << 3;  
01964 
01965     obsArray[i].cno = (float)rangecmp_cno + 20;
01966 
01967     // Reserved (22 bits 170-191)
01968     obsArray[i].reserved  = (message[index] & 0xFC )>> 5; index ++ ;
01969     obsArray[i].reserved |= message[index] << 8;          index ++ ;
01970     obsArray[i].reserved |= message[index] << 16;         index ++ ;
01971   }
01972 
01973   return TRUE;
01974 }
01975 
01976 BOOL NOVATELOEM4_DecodeRANGEB(
01977   const unsigned char *message,            //!< The message buffer containing a complete RANGEB message (input).
01978   const unsigned short messageLength,      //!< The length of the entire message (input).
01979   NOVATELOEM4_structBinaryHeader* header,  //!< A pointer to a NovAtel OEM4 header information struct (output).
01980   NOVATELOEM4_structObservation* obsArray, //!< A pointer to a user provided array of struct_NOVATELOEM4_RANGE (output).
01981   const unsigned char maxNrObs,            //!< The maximum number of elements in the array provided (input).
01982   unsigned *nrObs                          //!< The number of valid elements set in the array (output).
01983   )
01984 {
01985   unsigned i = 0;                 // A counter.
01986   unsigned j = 0;                 // A counter.
01987   unsigned index = 0;             // An index into the message buffer.
01988   unsigned char headerLength = 0; // The length of the header only as indicated in the header.
01989   unsigned short dataLength = 0;  // The length of the data part of the message as indicated in the header.
01990   unsigned short msgLength = 0;   // The computed length of the entire message.
01991   unsigned short testLength = 0;  // The expected length of the data given the number of observations.
01992   unsigned char dbytes[8];        // Enough bytes to store a double.
01993   unsigned char fbytes[4];        // Enough bytes to store a float.
01994   double *dptr;                   // A pointer to a double.
01995   float *fptr;                    // A pointer to a float.
01996   
01997   // Perform sanity checks.
01998   if( message == NULL )
01999   {
02000     GNSS_ERROR_MSG( "if( message == NULL )" );
02001     return FALSE;
02002   }
02003   if( obsArray == NULL )
02004   {
02005     GNSS_ERROR_MSG( "if( obsArray == NULL )" );
02006     return FALSE;
02007   }
02008   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x12 ) // sync must be present
02009   {
02010     GNSS_ERROR_MSG( "sync not present" );
02011     return FALSE;
02012   }
02013 
02014   // Decode the binary header.
02015   if( !NOVATELOEM4_DecodeBinaryMessageHeader( message, messageLength, header ) )
02016   {
02017     GNSS_ERROR_MSG( "NOVATELOEM4_DecodeBinaryMessageHeader returned FALSE." );
02018     return FALSE;
02019   }
02020 
02021   // Get the header length.
02022   headerLength = message[3];
02023 
02024   // Get the data length.
02025   dataLength = message[8];
02026   dataLength |= message[9] << 8;
02027 
02028   // Check that the data length + header length + 4 (crc) == messageLength provided.
02029   msgLength = dataLength + headerLength + 4;
02030   if( msgLength != messageLength )
02031   {
02032     GNSS_ERROR_MSG( "if( msgLength != messageLength )" );
02033     return FALSE;
02034   }
02035 
02036   // Get the number of observations.
02037   index = headerLength;
02038   *nrObs = message[index]; 
02039   index++;
02040   *nrObs |= message[index] << 8;
02041   index++;
02042   *nrObs |= message[index] << 16;
02043   index++;
02044   *nrObs |= message[index] << 24;
02045 
02046   // Check that there is enough room in the array provided.
02047   if( maxNrObs < *nrObs )
02048   {
02049     GNSS_ERROR_MSG( "if( maxNrObs < *nrObs )" );
02050     return FALSE;
02051   }
02052 
02053   // Check that the number of observations fits the data length given.
02054   testLength = (unsigned short)(*nrObs*44 + 4);
02055   if( testLength != dataLength )
02056   {
02057     GNSS_ERROR_MSG( "if( testLength != dataLength )" );
02058     return FALSE;
02059   }
02060 
02061   // Decode the data.
02062   index = headerLength+4;
02063   for( i = 0; i < *nrObs; i++ )
02064   {
02065     obsArray[i].prn       = message[index];      index++;
02066     obsArray[i].prn      |= message[index] << 8; index++;
02067     obsArray[i].reserved  = message[index];      index++;
02068     obsArray[i].reserved |= message[index] << 8; index++;
02069     
02070     for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02071     dptr = (double*)&dbytes;
02072     obsArray[i].psr = *dptr;
02073 
02074     for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02075     fptr = (float*)&fbytes;
02076     obsArray[i].psrstd = *fptr;
02077 
02078     for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02079     dptr = (double*)&dbytes;
02080     obsArray[i].adr = *dptr;
02081 
02082     for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02083     fptr = (float*)&fbytes;
02084     obsArray[i].adrstd = *fptr;
02085 
02086     for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02087     fptr = (float*)&fbytes;
02088     obsArray[i].doppler = *fptr;
02089 
02090     for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02091     fptr = (float*)&fbytes;
02092     obsArray[i].cno = *fptr;
02093 
02094     for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02095     fptr = (float*)&fbytes;
02096     obsArray[i].locktime = *fptr;
02097 
02098     obsArray[i].rawTrackingStatus  = message[index];       index++;
02099     obsArray[i].rawTrackingStatus |= message[index] <<  8; index++;
02100     obsArray[i].rawTrackingStatus |= message[index] << 16; index++;
02101     obsArray[i].rawTrackingStatus |= message[index] << 24; index++;
02102 
02103     if( !NOVATELOEM4_DecodeTrackingStatus( obsArray[i].rawTrackingStatus, &obsArray[i].trackingStatus ) )    
02104     {
02105       GNSS_ERROR_MSG( "NOVATELOEM4_DecodeTrackingStatus returned FALSE." );
02106       return FALSE;    
02107     }
02108   }
02109  
02110   return TRUE;
02111 }
02112 
02113 
02114 BOOL NOVATELOEM4_DecodeBESTPOSB(
02115   const unsigned char *message,            //!< The message buffer containing a complete RANGEB message (input).
02116   const unsigned short messageLength,      //!< The length of the entire message (input).
02117   NOVATELOEM4_structBinaryHeader* header,  //!< A pointer to a NovAtel OEM4 header information struct (output).
02118   NOVATELOEM4_structBestPosition* bestpos  //!< A pointer to a NovAtel OEM4 best position information struct (output).
02119   )
02120 {
02121   unsigned i = 0;                 // A counter.
02122   unsigned j = 0;                 // A counter.
02123   unsigned index = 0;             // An index into the message buffer.
02124   unsigned char headerLength = 0; // The length of the header only as indicated in the header.
02125   unsigned short dataLength = 0;  // The length of the data part of the message as indicated in the header.  
02126   unsigned short msgLength = 0;   // The computed length of the entire message.
02127   unsigned char dbytes[8];        // Enough bytes to store a double.
02128   unsigned char fbytes[4];        // Enough bytes to store a float.
02129   double *dptr;                   // A pointer to a double.
02130   float *fptr;                    // A pointer to a float.
02131   unsigned utmp = 0;
02132   
02133   // Perform sanity checks.
02134   if( message == NULL )
02135   {
02136     GNSS_ERROR_MSG( "if( message == NULL )" );
02137     return FALSE;
02138   }
02139   if( header == NULL || bestpos == NULL )
02140   {
02141     GNSS_ERROR_MSG( "if( header == NULL || bestpos == NULL )" );
02142     return FALSE;
02143   }
02144   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x12 ) // sync must be present
02145   {
02146     GNSS_ERROR_MSG( "sync not present" );
02147     return FALSE;
02148   }
02149 
02150   // Decode the binary header.
02151   if( !NOVATELOEM4_DecodeBinaryMessageHeader( message, messageLength, header ) )
02152   {
02153     GNSS_ERROR_MSG( "NOVATELOEM4_DecodeBinaryMessageHeader returned FALSE." );
02154     return FALSE;
02155   }
02156 
02157   // Get the header length.
02158   headerLength = message[3];
02159 
02160   // Get the data length.
02161   dataLength = message[8];
02162   dataLength |= message[9] << 8;
02163 
02164   // Check that the data length + header length + 4 (crc) == messageLength provided.
02165   msgLength = dataLength + headerLength + 4;
02166   if( msgLength != messageLength )
02167   {
02168     GNSS_ERROR_MSG( "if( msgLength != messageLength )" );
02169     return FALSE;
02170   }
02171 
02172   // get the solution status.
02173   index = headerLength;
02174   utmp = message[index];        index++;
02175   utmp |= message[index] << 8;  index++;
02176   utmp |= message[index] << 16; index++;
02177   utmp |= message[index] << 24; index++;
02178   bestpos->solution_status = (NOVATELOEM4_enumSolutionStatus)(utmp);
02179 
02180   // get the solution type.
02181   utmp = message[index];        index++;
02182   utmp |= message[index] << 8;  index++;
02183   utmp |= message[index] << 16; index++;
02184   utmp |= message[index] << 24; index++;
02185   bestpos->solution_type = (NOVATELOEM4_enumSolutionType)(utmp);
02186 
02187   // get the latitude
02188   for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02189   dptr = (double*)&dbytes;
02190   bestpos->latitude_in_deg = *dptr;
02191 
02192   // get the longitude
02193   for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02194   dptr = (double*)&dbytes;
02195   bestpos->longitude_in_deg = *dptr;
02196 
02197   // get the height (msl)
02198   for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02199   dptr = (double*)&dbytes;
02200   bestpos->height_msl = *dptr;
02201 
02202   // get the undulation
02203   for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02204   fptr = (float*)&fbytes;
02205   bestpos->undulation = *fptr;
02206 
02207   // get the datum id.
02208   utmp = message[index];        index++;
02209   utmp |= message[index] << 8;  index++;
02210   utmp |= message[index] << 16; index++;
02211   utmp |= message[index] << 24; index++;
02212   bestpos->datum_id = utmp;
02213 
02214   // get the latitude standard deviation
02215   for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02216   fptr = (float*)&fbytes;
02217   bestpos->lat_std = *fptr;
02218 
02219   // get the longitude standard deviation
02220   for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02221   fptr = (float*)&fbytes;
02222   bestpos->lon_std = *fptr;
02223 
02224   // get the height standard deviation
02225   for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02226   fptr = (float*)&fbytes;
02227   bestpos->hgt_std = *fptr;
02228 
02229   // get the base station id
02230   bestpos->station_id[0] = message[index]; index++;
02231   bestpos->station_id[1] = message[index]; index++;
02232   bestpos->station_id[2] = message[index]; index++;
02233   bestpos->station_id[3] = message[index]; index++;
02234 
02235   // get the diff age
02236   for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02237   fptr = (float*)&fbytes;
02238   bestpos->diff_age = *fptr;
02239 
02240   // get the solution age
02241   for( j=0; j<4; j++ ){ fbytes[j] = message[index]; index++; }
02242   fptr = (float*)&fbytes;
02243   bestpos->sol_age = *fptr;
02244 
02245   bestpos->nr_obs_tracked = message[index]; index++;
02246   bestpos->nr_GPS_L1_ranges = message[index]; index++;
02247   bestpos->nr_GPS_L1_ranges_above_RTK_mask_angle = message[index]; index++;
02248   bestpos->nr_GPS_L2_ranges_above_RTK_mask_angle = message[index]; index++;
02249 
02250   bestpos->reserved[0] = message[index]; index++;
02251   bestpos->reserved[1] = message[index]; index++;
02252   bestpos->reserved[2] = message[index]; index++;
02253   bestpos->reserved[3] = message[index]; index++;
02254 
02255   return TRUE;
02256 }
02257 
02258 
02259 BOOL NOVATELOEM4_DecodeTIMEB(
02260   const unsigned char *message,            //!< The message buffer containing a complete RANGEB message (input).
02261   const unsigned short messageLength,      //!< The length of the entire message (input).
02262   NOVATELOEM4_structBinaryHeader* header,  //!< A pointer to a NovAtel OEM4 header information struct (output).
02263   NOVATELOEM4_structTime* time_data        //!< A pointer to a NovAtel OEM4 best position information struct (output).
02264   )
02265 {
02266   unsigned i = 0;                 // A counter.
02267   unsigned j = 0;                 // A counter.
02268   unsigned index = 0;             // An index into the message buffer.
02269   unsigned char headerLength = 0; // The length of the header only as indicated in the header.
02270   unsigned short dataLength = 0;  // The length of the data part of the message as indicated in the header.  
02271   unsigned short msgLength = 0;   // The computed length of the entire message.
02272   unsigned char dbytes[8];        // Enough bytes to store a double.
02273   double *dptr;                   // A pointer to a double.
02274   unsigned utmp = 0;
02275   
02276   // Perform sanity checks.
02277   if( message == NULL )
02278   {
02279     GNSS_ERROR_MSG( "if( message == NULL )" );
02280     return FALSE;
02281   }
02282   if( header == NULL || time_data == NULL )
02283   {
02284     GNSS_ERROR_MSG( "if( header == NULL || time_data == NULL )" );
02285     return FALSE;
02286   }
02287   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x12 ) // sync must be present
02288   {
02289     GNSS_ERROR_MSG( "sync not present" );
02290     return FALSE;
02291   }
02292 
02293   // Decode the binary header.
02294   if( !NOVATELOEM4_DecodeBinaryMessageHeader( message, messageLength, header ) )
02295   {
02296     GNSS_ERROR_MSG( "NOVATELOEM4_DecodeBinaryMessageHeader returned FALSE." );
02297     return FALSE;
02298   }
02299 
02300   // Get the header length.
02301   headerLength = message[3];
02302 
02303   // Get the data length.
02304   dataLength = message[8];
02305   dataLength |= message[9] << 8;
02306 
02307   // Check that the data length + header length + 4 (crc) == messageLength provided.
02308   msgLength = dataLength + headerLength + 4;
02309   if( msgLength != messageLength )
02310   {
02311     GNSS_ERROR_MSG( "if( msgLength != messageLength )" );
02312     return FALSE;
02313   }
02314 
02315   // get the clock status.
02316   index = headerLength;
02317   utmp  = message[index];       index++;
02318   utmp |= message[index] << 8;  index++;
02319   utmp |= message[index] << 16; index++;
02320   utmp |= message[index] << 24; index++;
02321   time_data->clock_status = (NOVATELOEM4_enumClockStatus)(utmp);
02322 
02323   // get the rx clock offset
02324   for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02325   dptr = (double*)&dbytes;
02326   time_data->receiver_clock_offset = *dptr;
02327 
02328   // get the rx clock offset std
02329   for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02330   dptr = (double*)&dbytes;
02331   time_data->receiver_clock_offset_std = *dptr;
02332 
02333   // get the utc offset
02334   for( j=0; j<8; j++ ){ dbytes[j] = message[index]; index++; }
02335   dptr = (double*)&dbytes;
02336   time_data->utc_offset = *dptr;
02337 
02338   // get the utc year
02339   utmp  = message[index];       index++;
02340   utmp |= message[index] << 8;  index++;
02341   utmp |= message[index] << 16; index++;
02342   utmp |= message[index] << 24; index++;
02343   time_data->utc_year = utmp;
02344 
02345   time_data->utc_month = message[index]; index++;
02346   time_data->utc_day = message[index]; index++;
02347   time_data->utc_hour = message[index]; index++;
02348   time_data->utc_minute = message[index]; index++;
02349 
02350   utmp  = message[index];       index++;
02351   utmp |= message[index] << 8;  index++;
02352   utmp |= message[index] << 16; index++;
02353   utmp |= message[index] << 24; index++;
02354   time_data->utc_milliseconds = utmp;  
02355 
02356   utmp  = message[index];       index++;
02357   utmp |= message[index] << 8;  index++;
02358   utmp |= message[index] << 16; index++;
02359   utmp |= message[index] << 24; index++;
02360   if( utmp == 0 )
02361     time_data->isUTCValid = FALSE;
02362   else
02363     time_data->isUTCValid = TRUE;
02364 
02365   return TRUE;
02366 }
02367 
02368 
02369 
02370 
02371 BOOL NOVATELOEM4_DecodeTrackingStatus(
02372   const unsigned rawTrackingStatus,                 //!< The raw 32 bit tracking status value.
02373   NOVATELOEM4_structTrackingStatus *trackingStatus  //!< The decoded tracking status information.
02374   )
02375 {
02376   // local typedef
02377   typedef struct
02378   {
02379     unsigned trackingState          :5;
02380     unsigned channelNumber          :5;
02381     unsigned phaseLockFlag          :1;
02382     unsigned parityKnownFlag        :1;
02383     unsigned codeLockedFlag         :1;
02384     unsigned correlatorSpacing      :3;
02385     unsigned satelliteSystem        :3;
02386     unsigned reserved1              :1;
02387     unsigned grouping               :1;
02388     unsigned frequency              :2;
02389     unsigned codeType               :3;
02390     unsigned forwardErrorCorrection :1;
02391     unsigned primaryL1Channel       :1;
02392     unsigned halfCycleFlag          :1;
02393     unsigned reserved3              :1;
02394     unsigned prnLockFlag            :1;
02395     unsigned channelAssignment      :1;
02396   } NOVATELOEM4_channelStatusBitField; // 0-31 bits
02397 
02398   NOVATELOEM4_channelStatusBitField bitField;
02399   NOVATELOEM4_channelStatusBitField *ptrBitField;
02400 
02401   if( trackingStatus == NULL )
02402   {
02403     GNSS_ERROR_MSG( "if( trackingStatus == NULL )" );
02404     return FALSE;
02405   }
02406 
02407   ptrBitField = (NOVATELOEM4_channelStatusBitField *)&rawTrackingStatus;
02408   bitField = *ptrBitField;
02409 
02410   trackingStatus->eTrackingState     = (NOVATELOEM4_enumTrackingState)bitField.trackingState;
02411   trackingStatus->channelNumber      = bitField.channelNumber;
02412   trackingStatus->isPhaseLocked      = bitField.phaseLockFlag;
02413   trackingStatus->isParityKnown      = bitField.parityKnownFlag;
02414   trackingStatus->isCodeLocked       = bitField.codeLockedFlag;
02415   trackingStatus->eCorrelatorSpacing = (NOVATELOEM4_enumCorrelatorSpacing)bitField.correlatorSpacing;
02416   trackingStatus->eSatelliteSystem   = (NOVATELOEM4_enumSatelliteSystem)bitField.satelliteSystem;
02417   trackingStatus->isGrouped          = bitField.grouping;
02418   trackingStatus->eFrequency         = (NOVATELOEM4_enumFrequency)bitField.frequency;
02419   trackingStatus->eCodeType          = (NOVATELOEM4_enumCodeType)bitField.codeType;
02420   trackingStatus->isFECEnabled       = bitField.forwardErrorCorrection;
02421   trackingStatus->isPrimaryL1Channel = bitField.primaryL1Channel;
02422   trackingStatus->isHalfCycleAdded   = bitField.halfCycleFlag;
02423   trackingStatus->isForcedAssignment = bitField.channelAssignment;
02424 
02425   return TRUE;
02426 }
02427 
02428 
02429 BOOL NOVATELOEM4_DecodeRAWEPHEMB(
02430   const unsigned char *message,           //!< The message buffer containing a complete RANGEB message (input).
02431   const unsigned short messageLength,     //!< The length of the entire message (input).
02432   NOVATELOEM4_structBinaryHeader* header, //!< A pointer to a NovAtel OEM4 header information struct (output).
02433   unsigned *prn,                          //!< The satellite PRN number.
02434   unsigned *reference_week,               //!< The reference GPS week (0-1024+) [weeks].
02435   unsigned *reference_time,               //!< The reference GPS time of week (0-604800) [s].
02436   unsigned       *tow,                    //!< The time of week in subframe1, the time of the leading bit edge of subframe 2 [s]
02437   unsigned short *iodc,                   //!< 10 bit issue of data (clock), 8 LSB bits will match the iode                  []    
02438   unsigned char  *iode,                   //!< 8 bit  issue of data (ephemeris)                                              []
02439   unsigned       *toe,                    //!< reference time ephemeris (0-604800)                                           [s]
02440   unsigned       *toc,                    //!< reference time (clock)   (0-604800)                                           [s]      
02441   unsigned short *week,                   //!< 10 bit gps week 0-1023 (user must account for week rollover )                 [week]    
02442   unsigned char  *health,                 //!< 6 bit health parameter, 0 if healthy, unhealth othersize                      [0=healthy]    
02443   unsigned char  *alert_flag,             //!< 1 = URA may be worse than indicated                                           [0,1]
02444   unsigned char  *anti_spoof,             //!< anti-spoof flag from 0=off, 1=on                                              [0,1]    
02445   unsigned char  *code_on_L2,             //!< 0=reserved, 1=P code on L2, 2=C/A on L2                                       [0,1,2]
02446   unsigned char  *ura,                    //!< User Range Accuracy lookup code, 0 is excellent, 15 is use at own risk        [0-15], see p. 83 GPSICD200C
02447   unsigned char  *L2_P_data_flag,         //!< flag indicating if P is on L2 1=true                                          [0,1]
02448   unsigned char  *fit_interval_flag,      //!< fit interval flag (four hour interval or longer) 0=4 fours, 1=greater         [0,1]
02449   unsigned short *age_of_data_offset,     //!< age of data offset                                                            [s]
02450   double *tgd,     //!< group delay                                                                   [s]
02451   double *af2,     //!< polynomial clock correction coefficient (rate of clock drift)                 [s/s^2]
02452   double *af1,     //!< polynomial clock correction coefficient (clock drift)                         [s/s]
02453   double *af0,     //!< polynomial clock correction coefficient (clock bias)                          [s]    
02454   double *m0,      //!< mean anomaly at reference time                                                [rad]
02455   double *delta_n, //!< mean motion difference from computed value                                    [rad/s]
02456   double *ecc,     //!< eccentricity                                                                  []
02457   double *sqrta,   //!< square root of the semi-major axis                                            [m^(1/2)]
02458   double *omega0,  //!< longitude of ascending node of orbit plane at weekly epoch                    [rad]
02459   double *i0,      //!< inclination angle at reference time                                           [rad]
02460   double *w,       //!< argument of perigee                                                           [rad]
02461   double *omegadot,//!< rate of right ascension                                                       [rad/s]
02462   double *idot,    //!< rate of inclination angle                                                     [rad/s]
02463   double *cuc,     //!< amplitude of the cosine harmonic correction term to the argument of latitude  [rad]
02464   double *cus,     //!< amplitude of the sine harmonic correction term to the argument of latitude    [rad]
02465   double *crc,     //!< amplitude of the cosine harmonic correction term to the orbit radius          [m]
02466   double *crs,     //!< amplitude of the sine harmonic correction term to the orbit radius            [m]
02467   double *cic,     //!< amplitude of the cosine harmonic correction term to the angle of inclination  [rad]
02468   double *cis      //!< amplitude of the sine harmonic correction term to the angle of inclination    [rad]
02469   )
02470 {
02471   unsigned short msgLength; // The computed message length [bytes].
02472   unsigned index = 0;       // An index in to the message.
02473   BOOL result = FALSE;
02474 
02475   // Perform sanity checks.
02476   if( message == NULL )
02477   {
02478     GNSS_ERROR_MSG( "if( message == NULL )" );
02479     return FALSE;
02480   }
02481   if( message[0] != 0xAA || message[1] != 0x44 || message[2] != 0x12 ) // sync must be present
02482   {
02483     GNSS_ERROR_MSG( "sync not present" );    
02484     return FALSE;
02485   }
02486 
02487   // Decode the binary header.
02488   if( !NOVATELOEM4_DecodeBinaryMessageHeader( message, messageLength, header ) )
02489   {
02490     GNSS_ERROR_MSG( "NOVATELOEM4_DecodeBinaryMessageHeader returned FALSE." );
02491     return FALSE;
02492   }
02493 
02494   // Check that the length of the message matches the header information.
02495   msgLength = header->headerLength + header->dataLength + 4;
02496   if( msgLength != messageLength )
02497   {
02498     GNSS_ERROR_MSG( "if( msgLength != messageLength )" );
02499     return FALSE;
02500   }
02501 
02502   index = header->headerLength;
02503   *prn  = message[index];       index++;
02504   *prn |= message[index] << 8;  index++;
02505   *prn |= message[index] << 16; index++;
02506   *prn |= message[index] << 24; index++;
02507 
02508   *reference_week  = message[index];       index++;
02509   *reference_week |= message[index] << 8;  index++;
02510   *reference_week |= message[index] << 16; index++;
02511   *reference_week |= message[index] << 24; index++;
02512 
02513   *reference_time  = message[index];       index++;
02514   *reference_time |= message[index] << 8;  index++;
02515   *reference_time |= message[index] << 16; index++;
02516   *reference_time |= message[index] << 24; index++;
02517 
02518   result = GPS_DecodeRawGPSEphemeris(
02519     &message[index],
02520     &message[index+30],
02521     &message[index+60],    
02522     (unsigned short)(*prn),
02523     tow,
02524     iodc,
02525     iode,  
02526     toe,   
02527     toc,   
02528     week,  
02529     health,
02530     alert_flag,
02531     anti_spoof,
02532     code_on_L2,
02533     ura,       
02534     L2_P_data_flag,
02535     fit_interval_flag,
02536     age_of_data_offset, 
02537     tgd,                
02538     af2,                
02539     af1,                
02540     af0,                
02541     m0,                
02542     delta_n,           
02543     ecc,               
02544     sqrta,             
02545     omega0,            
02546     i0,                
02547     w,                 
02548     omegadot,          
02549     idot,              
02550     cuc,               
02551     cus,               
02552     crc,               
02553     crs,               
02554     cic,               
02555     cis                
02556     );
02557   if( !result )
02558   {
02559     GNSS_ERROR_MSG( "GPS_DecodeRawGPSEphemeris returned FALSE." );    
02560     return FALSE;
02561   }
02562 
02563   return TRUE;
02564 }
SourceForge.net Logo