gpsppssync_main.cpp

Go to the documentation of this file.
00001 /**
00002 \file    gpsppssync_main.cpp
00003 \brief   The main function for gpsppssync.
00004 
00005 \author  Glenn D. MacGougan (GDM)
00006 \date    2008-12-22
00007 \since   2008-12-22
00008 
00009 \b "LICENSE INFORMATION" \n
00010 Copyright (c) 2008 - All rights reserved. \n
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided the following conditions are met: \n
00014 
00015 - Redistributions of source code must retain the above copyright
00016   notice, this list of conditions and the following disclaimer. \n
00017 - Redistributions in binary form must reproduce the above copyright
00018   notice, this list of conditions and the following disclaimer in the
00019   documentation and/or other materials provided with the distribution. \n
00020 - The name(s) of the contributor(s) may not be used to endorse or promote 
00021   products derived from this software without specific prior written 
00022   permission. \n
00023 
00024 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00025 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00026 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00028 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00030 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00031 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00032 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00033 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00034 SUCH DAMAGE.
00035 */
00036 
00037 #include <windows.h>
00038 #include <process.h>
00039 #include <math.h>
00040 #include <string> // for std::string
00041 #include <time.h>
00042 #include <queue>
00043 #include "SerialPortClass.h"
00044 #include "novatel.h"
00045 #include "time_conversion.h"
00046 #include "gpsppssync_OptionFile.h"
00047 #include "gnss_error.h"
00048 
00049 #define PACKET_SIZE (16384)
00050 #define BIG_BUFFER_SIZE (1024*1024) // 1 MB
00051 
00052 using namespace std;
00053 
00054 
00055 struct stUTC
00056 {
00057   unsigned short year;     // Universal Time Coordinated    [year]
00058   unsigned char  month;    // Universal Time Coordinated    [1-12 months] 
00059   unsigned char  day;      // Universal Time Coordinated    [1-31 days]
00060   unsigned char  hour;     // Universal Time Coordinated    [hours]
00061   unsigned char  minute;   // Universal Time Coordinated    [minutes]
00062   float          seconds;  // Universal Time Coordinated    [s]
00063 
00064   stUTC(): year(0), month(0), day(0), hour(0), minute(0), seconds(0.0){}
00065 };
00066 
00067 struct stPCTime
00068 {
00069   unsigned short  utc_year;     // Universal Time Coordinated    [year]
00070   unsigned char   utc_month;    // Universal Time Coordinated    [1-12 months] 
00071   unsigned char   utc_day;      // Universal Time Coordinated    [1-31 days]
00072   unsigned char   utc_hour;     // Universal Time Coordinated    [hours]
00073   unsigned char   utc_minute;   // Universal Time Coordinated    [minutes]
00074   float           utc_seconds;  // Universal Time Coordinated    [s]
00075   unsigned char   utc_offset;
00076   unsigned short  gps_week;
00077   double          gps_tow;
00078   double          jd;
00079 };
00080 
00081 
00082 
00083 /// A non-threaded function to open a com port to an oem3 and sync the PC time to GPS time
00084 /// using serial communications to establish coarse time, then using the PPS which is connected
00085 /// to pin 9 of the serial link to establish fine time.
00086 bool PerformGPSPCTimeSync_NovAtelOEM3( 
00087   const unsigned SerialPortNumber, //!< The COM port number.
00088   const unsigned SerialPortNumberOnReceiver, //!< The COM port number to log data from on the receiver.
00089   const bool PerformPPSTest,       //!< A boolean to indicate if the pulse per second (on pin 9, ring indicator pin) is to be used for fine time synchronization.
00090   const bool AllowTimeForHyperTerminalComparison //!< A boolean to indicate if 40s with time display and audible dings are to be used to check the synchronization manually.
00091   );
00092 
00093 /// A non-threaded function to open a com port to an oem4 and sync the PC time to GPS time
00094 /// using serial communications to establish coarse time, then using the PPS which is connected
00095 /// to pin 9 of the serial link to establish fine time.
00096 bool PerformGPSPCTimeSync_NovAtelOEM4( 
00097   const unsigned SerialPortNumber, //!< The COM port number.
00098   const unsigned SerialPortNumberOnReceiver, //!< The COM port number to log data from on the receiver.
00099   const bool PerformPPSTest,       //!< A boolean to indicate if the pulse per second (on pin 9, ring indicator pin) is to be used for fine time synchronization.
00100   const bool AllowTimeForHyperTerminalComparison //!< A boolean to indicate if 40s with time display and audible dings are to be used to check the synchronization manually.
00101   );
00102 
00103 
00104 /// Send a message to the receiver. Echo the command to the terminal.
00105 bool SendCommand( SerialPort& port, std::string msg );
00106 
00107 
00108 int main( int argc, char* argv[] )
00109 {
00110   try
00111   {
00112     gpsppssync_OptionFile opt;
00113     char buffer[8192];   // A c style string buffer.
00114     unsigned i = 0;
00115     
00116     // set the buffer to zero.
00117     memset( buffer, 0, 512 );
00118 
00119     // Check the arguments
00120     if( argc != 2 )
00121     {
00122       printf( "USAGE: gpsppssync <option filename>\n" );
00123       return 0;
00124     }
00125     
00126     // Get the options.
00127     if( !opt.ReadAndInterpretOptions( argv[1] ) )
00128     {
00129       printf( "opt.ReadFromFile returned false.\n" );
00130       return -1;
00131     }
00132 
00133     if( opt.m_ReceiverType.compare( "NOVATELOEM3" ) == 0 )
00134     {
00135       if( !PerformGPSPCTimeSync_NovAtelOEM3( opt.m_SerialPortNumber, opt.m_ReceiverSerialPortNumber, opt.m_PerformPPSTest, opt.m_AllowTimeForHyperTerminalComparison ) )
00136       {
00137         printf( "PerformGPSPCTimeSync_NovAtelOEM3 returned false.\n" );
00138         return -1;
00139       }
00140     }
00141     else if( opt.m_ReceiverType.compare( "NOVATELOEM4" ) == 0 || opt.m_ReceiverType.compare( "NOVATELOEMV" ) == 0 )
00142     {
00143       if( !PerformGPSPCTimeSync_NovAtelOEM4( opt.m_SerialPortNumber, opt.m_ReceiverSerialPortNumber, opt.m_PerformPPSTest, opt.m_AllowTimeForHyperTerminalComparison ) )
00144       {
00145         printf( "PerformGPSPCTimeSync_NovAtelOEM4 returned false.\n" );
00146         return -1;
00147       }
00148     }
00149 
00150     printf( "Shutting down.\n" );
00151     Sleep(1500);
00152   }
00153   catch( ... )
00154   {
00155 
00156   }
00157   return 0;
00158 }
00159 
00160 
00161 
00162 bool PerformGPSPCTimeSync_NovAtelOEM3( 
00163   const unsigned SerialPortNumber, //!< The COM port number.
00164   const unsigned SerialPortNumberOnReceiver, //!< The COM port number to log data from on the receiver.
00165   const bool PerformPPSTest,       //!< A boolean to indicate if the pulse per second (on pin 9, ring indicator pin) is to be used for fine time synchronization.
00166   const bool AllowTimeForHyperTerminalComparison //!< A boolean to indicate if 40s with time display and audible dings are to be used to check the synchronization manually.
00167   )
00168 {
00169   SerialPort port;
00170   unsigned char readbuf[PACKET_SIZE];
00171   unsigned char buffer[PACKET_SIZE];
00172   unsigned char message[PACKET_SIZE];
00173   unsigned messageLength = 0;
00174   unsigned nrBytesRead = 0;
00175   unsigned nrBytesInBuffer = 0;
00176   unsigned offset = 0;
00177   BOOL result = 0;
00178   BOOL wasEndOfBufferReached = FALSE;
00179   BOOL wasMessageFound = FALSE;
00180   unsigned startPosition = 0;
00181   unsigned messageID = 0;
00182   unsigned nrBadCheckums = 0;
00183   int method = 0;
00184   unsigned count = 0;
00185   unsigned i = 0;
00186   std::string msg;
00187   
00188   stUTC utc;
00189 
00190   double rs232_transmission_time = 0;
00191   
00192   stPCTime pc_time;
00193 
00194   // A container for the POSB message info.
00195   struct
00196   {
00197     unsigned short gps_week;
00198     double gps_tow;
00199     double lat;
00200     double lon;
00201     double hgt;
00202     double lat_std;
00203     double lon_std;
00204     double hgt_std;
00205     double undulation;
00206     unsigned datum_id;
00207     NOVATELOEM3_enumSolutionStatus status;    
00208   } posb;
00209 
00210   // A container for the TM1B messsage info.
00211   struct
00212   {
00213     unsigned short gps_week;
00214     double gps_tow;
00215     double clk_offset;
00216     double clk_offset_std;
00217     double utc_offset; 
00218     BOOL is_clk_stabilized;
00219   } tm1b;
00220   
00221   clock_t c0;
00222   clock_t c1;
00223   double elapsed_time_s = 0;
00224   bool isPositionValid = false;
00225 
00226   bool coarse_sync_success = false;
00227   bool pps_sync_success = false;
00228   bool ring_detected = false;
00229   bool wasDataReceived = false;
00230   unsigned pulse_count = 0;
00231 
00232   // Operate this thread at high class priority and high thread priority so that the 
00233   // time synchronization is accurate.
00234   //SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS );
00235   SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS );  
00236   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
00237 
00238   if( !port.Open( (unsigned short)SerialPortNumber, SERIALPORT_BAUD_115200 ) )
00239   {
00240     printf( "Unable to open port %d.", SerialPortNumber );
00241     return false;
00242   }
00243   Sleep(50);
00244 
00245   printf( "Performing GPS - PC time synchronization.\n" );
00246 
00247   sprintf( (char*)message, "unlogall COM%d\r", SerialPortNumberOnReceiver );
00248   msg = (char*)message;
00249   SendCommand( port, msg );
00250 
00251   // First ensure the receiver has a valid position.
00252   sprintf( (char*)message, "log com%d POSB ontime 2.0\r", SerialPortNumberOnReceiver );
00253   msg = (char*)message;
00254   SendCommand( port, msg );
00255 
00256   // Flush the com port input buffer
00257   memset( readbuf, 0, PACKET_SIZE );
00258   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00259   {
00260     printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00261     return false;
00262   }
00263   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00264   {
00265     printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00266     return false;
00267   }
00268 
00269   c0 = clock();
00270   while( elapsed_time_s < 30.0 && isPositionValid == false )
00271   {
00272     memset( readbuf, 0, PACKET_SIZE );
00273     if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00274     {
00275       printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00276       return false;
00277     }
00278 
00279     if( nrBytesRead > 0 )
00280     {
00281       printf( "%d bytes read.\n", nrBytesRead );
00282       if( nrBytesRead + offset > PACKET_SIZE )
00283       {
00284         printf( "Unexpected.\n");
00285         return false;
00286       }
00287       memcpy( buffer+offset, readbuf, nrBytesRead );
00288       nrBytesInBuffer += nrBytesRead;
00289       offset = nrBytesInBuffer;
00290 
00291       if( nrBytesInBuffer > 12 )
00292       {
00293         result = NOVATELOEM3_FindNextMessageInBuffer(
00294           buffer,
00295           PACKET_SIZE,
00296           message,
00297           PACKET_SIZE,
00298           &wasEndOfBufferReached,
00299           &wasMessageFound,
00300           &startPosition,
00301           &messageLength,
00302           &messageID,
00303           &nrBadCheckums
00304           );
00305       }
00306       
00307       if( wasMessageFound && messageID == NOVATELOEM3_POSB )
00308       {
00309         result = NOVATELOEM3_DecodePOSB(
00310           message,
00311           messageLength,
00312           &posb.gps_week,
00313           &posb.gps_tow,
00314           &posb.lat,
00315           &posb.lon,
00316           &posb.hgt,
00317           &posb.undulation,
00318           &posb.datum_id,
00319           &posb.lat_std,
00320           &posb.lon_std,
00321           &posb.hgt_std,
00322           &posb.status
00323           );
00324 
00325         if( posb.status == NOVATELOEM3_SOLUTIONSTATUS_OK )
00326         {
00327           isPositionValid = true;
00328           continue;
00329         }
00330         else
00331         {
00332           offset = 0;
00333         }
00334       }
00335       else
00336       {
00337         offset = 0;
00338       
00339       }
00340     }
00341     Sleep(60);
00342     c1 = clock();
00343     elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
00344   }
00345 
00346   if( !isPositionValid )
00347   {
00348     printf( "The receiver position is not yet valid. Try again.\n" );
00349     return true;
00350   }
00351   else
00352   {
00353     printf( "A valid receiver position was verified.\n" );
00354   }
00355 
00356   // Get the receiver to log only TM1B messages ontime 5.0
00357   sprintf( (char*)message, "unlogall com%d\r", SerialPortNumberOnReceiver );
00358   msg = (char*)message;  
00359   SendCommand( port, msg );
00360 
00361   sprintf( (char*)message, "log com%d TM1B ontime 5.0\r", SerialPortNumberOnReceiver );
00362   msg = (char*)message;
00363   SendCommand( port, msg );
00364   Sleep(1500);
00365 
00366   // Flush the com port input buffer
00367   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00368   {
00369     printf( "port.Read returned false. port %d.\n", SerialPortNumber );    
00370     return false;
00371   }
00372   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00373   {
00374     printf( "port.Read returned false. port %d.\n", SerialPortNumber );    
00375     return false;
00376   }
00377   
00378   coarse_sync_success = false;
00379   tm1b.is_clk_stabilized = FALSE;
00380   c0 = clock();
00381   elapsed_time_s = 0;
00382   while( elapsed_time_s < 30.0 && coarse_sync_success == false )
00383   {
00384     memset( readbuf, 0, PACKET_SIZE );
00385     if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00386     {
00387       printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00388       return false;
00389     }
00390 
00391     if( nrBytesRead > 0 )
00392     {
00393       printf( "%d bytes read.\n", nrBytesRead );
00394       if( nrBytesRead + offset > PACKET_SIZE )
00395       {
00396         printf( "Unexpected.\n");
00397         return false;
00398       }
00399       memcpy( buffer+offset, readbuf, nrBytesRead );
00400       nrBytesInBuffer += nrBytesRead;
00401       offset = nrBytesInBuffer;
00402 
00403       if( nrBytesInBuffer > 12 )
00404       {
00405         result = NOVATELOEM3_FindNextMessageInBuffer(
00406           buffer,
00407           PACKET_SIZE,
00408           message,
00409           PACKET_SIZE,
00410           &wasEndOfBufferReached,
00411           &wasMessageFound,
00412           &startPosition,
00413           &messageLength,
00414           &messageID,
00415           &nrBadCheckums
00416           );
00417       }
00418       
00419       if( wasMessageFound && messageID == NOVATELOEM3_TM1B )
00420       {
00421         result = NOVATELOEM3_DecodeTM1B(
00422           message,
00423           messageLength,
00424           &tm1b.gps_week,
00425           &tm1b.gps_tow,
00426           &tm1b.clk_offset,
00427           &tm1b.clk_offset_std,
00428           &tm1b.utc_offset,
00429           &tm1b.is_clk_stabilized
00430           );
00431 
00432         if( tm1b.is_clk_stabilized )
00433         {
00434           tm1b.gps_week += 1024;
00435           result = TIMECONV_GetUTCTimeFromGPSTime(
00436             tm1b.gps_week,
00437             tm1b.gps_tow,
00438             &utc.year,
00439             &utc.month,
00440             &utc.day,
00441             &utc.hour,
00442             &utc.minute,
00443             &utc.seconds 
00444             );
00445           if( !result )
00446           {
00447             printf( "TIMECONV_GetUTCTimeFromGPSTime returned false.\n" );
00448             return false;
00449           }
00450           
00451           rs232_transmission_time = messageLength * 9.0 / 115200.0; // [s], 8 bits per byte + 1 stop bit
00452             
00453           utc.seconds -= (float)rs232_transmission_time;
00454 
00455           if( utc.seconds < 0 )
00456           {
00457             utc.seconds += 60.0;
00458             if( utc.minute == 0 )
00459             {
00460               utc.minute = 59;
00461               if( utc.hour == 0 )
00462               {
00463                 printf( "Too close to midnight to proceed.\n" );                
00464                 return true;
00465               }
00466               else
00467               {
00468                 utc.hour--;
00469               }
00470             }
00471             else
00472             {
00473               utc.minute--;
00474             }
00475           }
00476 
00477           // Set the PC time
00478           result = TIMECONV_SetSystemTime(
00479             utc.year,
00480             utc.month,
00481             utc.day,
00482             utc.hour,
00483             utc.minute,
00484             utc.seconds
00485             );              
00486 
00487           if( !result )
00488           {
00489             printf("TIMECONV_SetSystemTime returned FALSE.");            
00490             return false;
00491           }
00492           else
00493           {
00494             printf( "Coarse synchronization performed using TM1B message.\n" );
00495             coarse_sync_success = true;            
00496             continue;
00497           }
00498         }
00499         else
00500         {
00501           offset = 0;
00502         }
00503       }
00504       else
00505       {
00506         offset = 0;      
00507       }
00508     }
00509     Sleep(5);
00510     c1 = clock();
00511     elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
00512   }
00513 
00514   if( !coarse_sync_success )
00515   {
00516     printf( "Unable to achieve coarse synchronization. Please try again.\n" );
00517     return false;
00518   }
00519 
00520   sprintf( (char*)message, "unlogall com%d\r", SerialPortNumberOnReceiver );
00521   msg = (char*)message;
00522   SendCommand( port, msg );
00523 
00524   // Perform fine time synchronization.
00525   c0 = clock();
00526   elapsed_time_s = 0;
00527   while( elapsed_time_s < 30.0 && pps_sync_success == false )
00528   {
00529     double seconds = 0;
00530     port.WaitOnRingIndicator( 990, ring_detected );
00531     if( ring_detected )
00532     {
00533       result = TIMECONV_GetSystemTime(
00534         &pc_time.utc_year,
00535         &pc_time.utc_month, 
00536         &pc_time.utc_day,
00537         &pc_time.utc_hour,
00538         &pc_time.utc_minute,
00539         &pc_time.utc_seconds, 
00540         &pc_time.utc_offset, 
00541         &pc_time.jd, 
00542         &pc_time.gps_week, 
00543         &pc_time.gps_tow 
00544         );
00545       if( !result )
00546       {
00547         printf( "TIMECONV_GetSystemTime return false." );
00548         return false;
00549       }
00550       seconds = pc_time.utc_seconds;      
00551 
00552       pc_time.utc_seconds = floor( pc_time.utc_seconds + 1 );
00553       if( pc_time.utc_seconds == 60 )
00554       {
00555         pc_time.utc_seconds = 0;
00556         pc_time.utc_minute++;
00557         if( pc_time.utc_minute == 60 )
00558         {
00559           pc_time.utc_minute = 0;
00560           pc_time.utc_hour++;
00561           if( pc_time.utc_hour == 24 )
00562           {
00563             printf( "Too close to midnight to proceed\n" );
00564             return false;
00565           }
00566         }
00567       }
00568 
00569       pulse_count++;
00570       if( pulse_count == 5 )
00571       {
00572         result = TIMECONV_SetSystemTime(
00573           pc_time.utc_year,
00574           pc_time.utc_month,
00575           pc_time.utc_day,
00576           pc_time.utc_hour,
00577           pc_time.utc_minute,
00578           floor(pc_time.utc_seconds) 
00579           );
00580         if( !result )
00581         {
00582           printf( "TIMECONV_GetSystemTime return false." );
00583           return false;
00584         }
00585         else
00586         {
00587           pps_sync_success = true;
00588         }      
00589       }
00590       else
00591       {
00592         printf( "Pulse detected: Synchronizing in %d s.\n", 5-pulse_count );
00593       }
00594     }    
00595     else
00596     {
00597       printf( "%.0fs Remaining. Listening pin 9, ring indicator pin, of COM%d for PPS\n", 30.0 - elapsed_time_s, port.GetPortNumber() );
00598     }
00599     c1 = clock();
00600     elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
00601   }
00602 
00603   if( pps_sync_success )
00604   {
00605     printf( "Sync to PPS successful.\n" );
00606   }
00607   else
00608   {
00609     printf( "Failted to sync to PPS. Please try again.\n" );
00610     return true;
00611   }
00612 
00613   double mean_diff = 0;
00614   if( PerformPPSTest )
00615   {
00616     int pulsenr = 0;
00617     bool initc2 = true;
00618     clock_t c2;
00619     clock_t c3;
00620     double dt = 0;
00621     double diff = 0;    
00622 
00623     printf( "Performing PPS test.\n" );
00624 
00625     // Perform fine time synchronization.
00626     c0 = clock();
00627     elapsed_time_s = 0;
00628     while( elapsed_time_s < 60.0 )
00629     {
00630       port.WaitOnRingIndicator( 1005, ring_detected );      
00631       if( ring_detected )
00632       {
00633         if( initc2 )
00634         {
00635           c3 = c2 = clock();
00636           initc2 = false;
00637         }
00638         else
00639         {
00640           c3 = clock();
00641         }
00642         result = TIMECONV_GetSystemTime(
00643           &pc_time.utc_year,
00644           &pc_time.utc_month, 
00645           &pc_time.utc_day,
00646           &pc_time.utc_hour,
00647           &pc_time.utc_minute,
00648           &pc_time.utc_seconds, 
00649           &pc_time.utc_offset, 
00650           &pc_time.jd, 
00651           &pc_time.gps_week, 
00652           &pc_time.gps_tow 
00653         );
00654         if( !result )
00655         {
00656           printf( "TIMECONV_GetSystemTime return false." );
00657           return false;
00658         }
00659         dt = ((double)(c3-c2))/((double)CLOCKS_PER_SEC);
00660         if( pc_time.gps_tow - floor( pc_time.gps_tow ) > 0.5 )
00661           diff = -(floor( pc_time.gps_tow + 0.5 ) - pc_time.gps_tow)*1000.0;
00662         else
00663           diff = (pc_time.gps_tow - floor( pc_time.gps_tow ))*1000.0;
00664 
00665         mean_diff += diff;
00666 
00667         printf( "Pulse:%2d, dt:%.3f, PC(hh:mm:ss.sss): %02d:%02d:%06.3f difference:%.0f ms\n", pulsenr, dt, pc_time.utc_hour, pc_time.utc_minute, pc_time.utc_seconds, diff );
00668         pulsenr++;        
00669       }
00670       else
00671       {
00672         printf( "No ring.\n" );
00673       }
00674       c1 = clock();
00675       elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
00676     }
00677     printf( "Over 60 seconds, the difference in elapsed PC time is %.3f s\n", dt-60.0 );
00678     mean_diff/= (double)pulsenr;
00679     printf( "The mean pulse to pc time difference is: %.3f ms\n", mean_diff );
00680   }
00681 
00682 
00683   if( AllowTimeForHyperTerminalComparison )
00684   {
00685     sprintf( (char*)message, "log com%d gpzda ontime 1.0\r", SerialPortNumberOnReceiver );
00686     msg = (char*)message;
00687     SendCommand( port, msg );
00688 
00689     sprintf( (char*)message, "log com%d posa ontime 1.0\r", SerialPortNumberOnReceiver );
00690     msg = (char*)message;
00691     SendCommand( port, msg );
00692   }
00693 
00694   port.Close();
00695 
00696   
00697   if( AllowTimeForHyperTerminalComparison )
00698   {  
00699     printf( "The serial port is now closed you may open the port with hyperterminal for comparison.\n" );
00700     if( pps_sync_success )
00701     {
00702       count = 0;
00703       while( count < 40 )
00704       {
00705         TIMECONV_GetSystemTime(
00706           &pc_time.utc_year,
00707           &pc_time.utc_month,
00708           &pc_time.utc_day,
00709           &pc_time.utc_hour,
00710           &pc_time.utc_minute,
00711           &pc_time.utc_seconds,
00712           &pc_time.utc_offset,
00713           &pc_time.jd,
00714           &pc_time.gps_week,
00715           &pc_time.gps_tow
00716           );
00717         if( fabs(pc_time.utc_seconds - floor(pc_time.utc_seconds)) < 0.05 )
00718         {
00719           printf( "%02d:%02d:%.3f\t\t\t %d %.3f\n", pc_time.utc_hour, pc_time.utc_minute, pc_time.utc_seconds, pc_time.gps_week, pc_time.gps_tow );
00720           printf( "\a" );
00721           count++;
00722           Sleep(980);
00723         }
00724         Sleep(2);
00725       }
00726     }    
00727   }
00728 
00729   SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS );  
00730   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL );
00731 
00732   return true; 
00733 }
00734 
00735 
00736 bool PerformGPSPCTimeSync_NovAtelOEM4( 
00737   const unsigned SerialPortNumber, //!< The COM port number.
00738   const unsigned SerialPortNumberOnReceiver, //!< The COM port number to log data from on the receiver.
00739   const bool PerformPPSTest,       //!< A boolean to indicate if the pulse per second (on pin 9, ring indicator pin) is to be used for fine time synchronization.
00740   const bool AllowTimeForHyperTerminalComparison //!< A boolean to indicate if 40s with time display and audible dings are to be used to check the synchronization manually.
00741   )
00742 {
00743   SerialPort port;
00744   unsigned char readbuf[PACKET_SIZE];
00745   unsigned char buffer[PACKET_SIZE];
00746   unsigned char message[PACKET_SIZE];
00747   unsigned short messageLength = 0;
00748   unsigned nrBytesRead = 0;
00749   unsigned nrBytesInBuffer = 0;
00750   unsigned offset = 0;
00751   BOOL result = 0;
00752   BOOL wasEndOfBufferReached = FALSE;
00753   BOOL wasMessageFound = FALSE;
00754   unsigned startPosition = 0;
00755   unsigned short messageID = 0;
00756   unsigned nrBadCRC = 0;
00757   int method = 0;
00758   unsigned count = 0;
00759   unsigned i = 0;
00760   std::string msg;
00761   
00762   stUTC utc;
00763 
00764   double rs232_transmission_time = 0;
00765   
00766   stPCTime pc_time;
00767 
00768   NOVATELOEM4_structBinaryHeader  header;   
00769   NOVATELOEM4_structBestPosition  bestpos;
00770   NOVATELOEM4_structTime          time_data;
00771   
00772   clock_t c0;
00773   clock_t c1;
00774   double elapsed_time_s = 0;
00775   bool isPositionValid = false;
00776 
00777   bool coarse_sync_success = false;
00778   bool pps_sync_success = false;
00779   bool ring_detected = false;
00780   bool wasDataReceived = false;
00781   unsigned pulse_count = 0;
00782 
00783   // Operate this thread at high class priority and high thread priority so that the 
00784   // time synchronization is accurate.
00785   //SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS );
00786   SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS );  
00787   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
00788 
00789   if( !port.Open( (unsigned short)SerialPortNumber, SERIALPORT_BAUD_115200 ) )
00790   {
00791     printf( "Unable to open port %d.", SerialPortNumber );
00792     return false;
00793   }
00794   Sleep(50);
00795 
00796   printf( "Performing GPS - PC time synchronization.\n" );
00797 
00798   sprintf( (char*)message, "unlogall COM%d_ALL\r", SerialPortNumberOnReceiver );
00799   msg = (char*)message;
00800   SendCommand( port, msg );
00801 
00802   // First ensure the receiver has a valid position.
00803   sprintf( (char*)message, "log com%d BESTPOSB ontime 2.0\r", SerialPortNumberOnReceiver );
00804   msg = (char*)message;
00805   SendCommand( port, msg );
00806   Sleep(1500);
00807 
00808   // Flush the com port input buffer
00809   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00810   {
00811     printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00812     return false;
00813   }
00814   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00815   {
00816     printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00817     return false;
00818   }
00819   
00820   c0 = clock();
00821   while( elapsed_time_s < 30.0 && isPositionValid == false )
00822   {
00823     memset( readbuf, 0, PACKET_SIZE );
00824     if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00825     {
00826       printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00827       return false;
00828     }
00829 
00830     if( nrBytesRead > 0 )
00831     {
00832       printf( "%d bytes read.\n", nrBytesRead );
00833       if( nrBytesRead + offset > PACKET_SIZE )
00834       {
00835         printf( "Unexpected.\n");
00836         return false;
00837       }
00838       memcpy( buffer+offset, readbuf, nrBytesRead );
00839       nrBytesInBuffer += nrBytesRead;
00840       offset = nrBytesInBuffer;
00841 
00842       if( nrBytesInBuffer > 32 )
00843       {
00844         result = NOVATELOEM4_FindNextMessageInBuffer(
00845           buffer,
00846           PACKET_SIZE,
00847           message,
00848           PACKET_SIZE,
00849           &wasEndOfBufferReached,
00850           &wasMessageFound,
00851           &startPosition,
00852           &messageLength,
00853           &messageID,
00854           &nrBadCRC
00855           );
00856       }
00857       
00858       if( wasMessageFound && messageID == NOVATELOEM4_BESTPOSB )
00859       {
00860         result = NOVATELOEM4_DecodeBESTPOSB(
00861           message,
00862           messageLength,
00863           &header,
00864           &bestpos
00865           );
00866 
00867         if( bestpos.solution_status == NOVATELOEM4_SOLNSTATUS_SOL_COMPUTED )
00868         {
00869           isPositionValid = true;
00870           continue;
00871         }
00872         else
00873         {
00874           offset = 0;
00875         }
00876       }
00877       else
00878       {
00879         offset = 0;
00880       
00881       }
00882     }
00883     Sleep(60);
00884     c1 = clock();
00885     elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
00886   }
00887 
00888   if( !isPositionValid )
00889   {
00890     printf( "The receiver position is not yet valid. Try again.\n" );
00891     return true;
00892   }
00893   else
00894   {
00895     printf( "A valid receiver position was verified.\n" );
00896   }
00897 
00898   // Get the receiver to log only TIMEB messages ontime 5.0
00899   sprintf( (char*)message, "unlogall COM%d_ALL\r", SerialPortNumberOnReceiver );
00900   msg = (char*)message;  
00901   SendCommand( port, msg );
00902 
00903   sprintf( (char*)message, "log com%d TIMEB ontime 5.0\r", SerialPortNumberOnReceiver );
00904   msg = (char*)message;
00905   SendCommand( port, msg );
00906   Sleep(1500);
00907 
00908   // Flush the com port input buffer
00909   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00910   {
00911     printf( "port.Read returned false. port %d.\n", SerialPortNumber );    
00912     return false;
00913   }
00914   if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00915   {
00916     printf( "port.Read returned false. port %d.\n", SerialPortNumber );    
00917     return false;
00918   }
00919     
00920   coarse_sync_success = false;
00921   time_data.clock_status = NOVATELOEM4_CLOCK_STATUS_UNKNOWN;
00922   c0 = clock();
00923   elapsed_time_s = 0;
00924   while( elapsed_time_s < 30.0 && coarse_sync_success == false )
00925   {
00926     memset( readbuf, 0, PACKET_SIZE );
00927     if( !port.Read( readbuf, PACKET_SIZE, nrBytesRead ) )
00928     {
00929       printf( "port.Read returned false. port %d.\n", SerialPortNumber );
00930       return false;
00931     }
00932 
00933     if( nrBytesRead > 0 )
00934     {
00935       printf( "%d bytes read.\n", nrBytesRead );
00936       if( nrBytesRead + offset > PACKET_SIZE )
00937       {
00938         printf( "Unexpected.\n");
00939         return false;
00940       }
00941       memcpy( buffer+offset, readbuf, nrBytesRead );
00942       nrBytesInBuffer += nrBytesRead;
00943       offset = nrBytesInBuffer;
00944 
00945       if( nrBytesInBuffer > 32 )
00946       {
00947         result = NOVATELOEM4_FindNextMessageInBuffer(
00948           buffer,
00949           PACKET_SIZE,
00950           message,
00951           PACKET_SIZE,
00952           &wasEndOfBufferReached,
00953           &wasMessageFound,
00954           &startPosition,
00955           &messageLength,
00956           &messageID,
00957           &nrBadCRC
00958           );
00959       }
00960       
00961       if( wasMessageFound && messageID == NOVATELOEM4_TIMEB )
00962       {
00963         result = NOVATELOEM4_DecodeTIMEB(
00964           message,
00965           messageLength,
00966           &header,
00967           &time_data
00968           );
00969 
00970         if( time_data.clock_status == NOVATELOEM4_CLOCK_STATUS_VALID && time_data.isUTCValid )
00971         {
00972           utc.year = time_data.utc_year;
00973           utc.month = time_data.utc_month;
00974           utc.day = time_data.utc_day;
00975           utc.hour = time_data.utc_hour;
00976           utc.minute = time_data.utc_minute;
00977           utc.seconds = ((float)time_data.utc_milliseconds)/1000.0f;
00978           
00979           rs232_transmission_time = messageLength * 9.0 / 115200.0; // [s]
00980             
00981           utc.seconds -= (float)rs232_transmission_time;
00982 
00983           if( utc.seconds < 0 )
00984           {
00985             utc.seconds += 60.0;
00986             if( utc.minute == 0 )
00987             {
00988               utc.minute = 59;
00989               if( utc.hour == 0 )
00990               {
00991                 printf( "Too close to midnight to proceed.\n" );                
00992                 return true;
00993               }
00994               else
00995               {
00996                 utc.hour--;
00997               }
00998             }
00999             else
01000             {
01001               utc.minute--;
01002             }
01003           }
01004 
01005           result = TIMECONV_SetSystemTime(
01006             utc.year,
01007             utc.month,
01008             utc.day,
01009             utc.hour,
01010             utc.minute,
01011             utc.seconds
01012             );              
01013 
01014           if( !result )
01015           {
01016             printf("TIMECONV_SetSystemTime returned FALSE.");            
01017             return false;
01018           }
01019           else
01020           {
01021             printf( "Coarse synchronization performed using TIMEB message.\n" );
01022             coarse_sync_success = true;            
01023             continue;
01024           }
01025         }
01026         else
01027         {
01028           offset = 0;
01029         }
01030       }
01031       else
01032       {
01033         offset = 0;      
01034       }
01035     }
01036     Sleep(5);
01037     c1 = clock();
01038     elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
01039   }
01040 
01041   if( !coarse_sync_success )
01042   {
01043     printf( "Unable to achieve coarse synchronization. Please try again.\n" );
01044     return false;
01045   }
01046 
01047   sprintf( (char*)message, "unlogall COM%d_ALL\r", SerialPortNumberOnReceiver );
01048   msg = (char*)message;
01049   SendCommand( port, msg );
01050 
01051   // Perform fine time synchronization.
01052   c0 = clock();
01053   elapsed_time_s = 0;
01054   while( elapsed_time_s < 30.0 && pps_sync_success == false )
01055   {
01056     double seconds = 0;
01057     port.WaitOnRingIndicator( 990, ring_detected );
01058     if( ring_detected )
01059     {
01060       result = TIMECONV_GetSystemTime(
01061         &pc_time.utc_year,
01062         &pc_time.utc_month, 
01063         &pc_time.utc_day,
01064         &pc_time.utc_hour,
01065         &pc_time.utc_minute,
01066         &pc_time.utc_seconds, 
01067         &pc_time.utc_offset, 
01068         &pc_time.jd, 
01069         &pc_time.gps_week, 
01070         &pc_time.gps_tow 
01071         );
01072       if( !result )
01073       {
01074         printf( "TIMECONV_GetSystemTime return false." );
01075         return false;
01076       }
01077       seconds = pc_time.utc_seconds;      
01078 
01079       pc_time.utc_seconds = floor( pc_time.utc_seconds + 1 );
01080       if( pc_time.utc_seconds == 60 )
01081       {
01082         pc_time.utc_seconds = 0;
01083         pc_time.utc_minute++;
01084         if( pc_time.utc_minute == 60 )
01085         {
01086           pc_time.utc_minute = 0;
01087           pc_time.utc_hour++;
01088           if( pc_time.utc_hour == 24 )
01089           {
01090             printf( "Too close to midnight to proceed\n" );
01091             return false;
01092           }
01093         }
01094       }
01095 
01096       pulse_count++;
01097       if( pulse_count == 5 )
01098       {
01099         result = TIMECONV_SetSystemTime(
01100           pc_time.utc_year,
01101           pc_time.utc_month,
01102           pc_time.utc_day,
01103           pc_time.utc_hour,
01104           pc_time.utc_minute,
01105           floor(pc_time.utc_seconds) 
01106           );
01107         if( !result )
01108         {
01109           printf( "TIMECONV_GetSystemTime return false." );
01110           return false;
01111         }
01112         else
01113         {
01114           pps_sync_success = true;
01115         }      
01116       }
01117       else
01118       {
01119         printf( "Pulse detected: Synchronizing in %d s.\n", 5-pulse_count );
01120       }
01121     }    
01122     else
01123     {
01124       printf( "%.0fs Remaining. Listening pin 9, ring indicator pin, of COM%d for PPS\n", 30.0 - elapsed_time_s, port.GetPortNumber() );
01125     }
01126     c1 = clock();
01127     elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
01128   }
01129 
01130   if( pps_sync_success )
01131   {
01132     printf( "Sync to PPS successful.\n" );
01133   }
01134   else
01135   {
01136     printf( "Failted to sync to PPS. Please try again.\n" );
01137     return true;
01138   }
01139 
01140 
01141   double mean_diff = 0;
01142   if( PerformPPSTest )
01143   {
01144     int pulsenr = 0;
01145     bool initc2 = true;
01146     clock_t c2;
01147     clock_t c3;
01148     double dt = 0;
01149     double diff = 0;
01150    
01151     printf( "Performing PPS test.\n" );
01152 
01153     // Perform fine time synchronization.
01154     c0 = clock();
01155     elapsed_time_s = 0;
01156     while( elapsed_time_s < 60.0 )
01157     {
01158       port.WaitOnRingIndicator( 1005, ring_detected );      
01159       if( ring_detected )
01160       {
01161         if( initc2 )
01162         {
01163           c3 = c2 = clock();
01164           initc2 = false;
01165         }
01166         else
01167         {
01168           c3 = clock();
01169         }
01170         result = TIMECONV_GetSystemTime(
01171           &pc_time.utc_year,
01172           &pc_time.utc_month, 
01173           &pc_time.utc_day,
01174           &pc_time.utc_hour,
01175           &pc_time.utc_minute,
01176           &pc_time.utc_seconds, 
01177           &pc_time.utc_offset, 
01178           &pc_time.jd, 
01179           &pc_time.gps_week, 
01180           &pc_time.gps_tow 
01181         );
01182         if( !result )
01183         {
01184           printf( "TIMECONV_GetSystemTime return false." );
01185           return false;
01186         }
01187         dt = ((double)(c3-c2))/((double)CLOCKS_PER_SEC);
01188         if( pc_time.gps_tow - floor( pc_time.gps_tow ) > 0.5 )
01189           diff = -(floor( pc_time.gps_tow + 0.5 ) - pc_time.gps_tow)*1000.0;
01190         else
01191           diff = (pc_time.gps_tow - floor( pc_time.gps_tow ))*1000.0;
01192 
01193         mean_diff += diff;
01194 
01195         printf( "Pulse:%2d, dt:%.3f, PC(hh:mm:ss.sss): %02d:%02d:%06.3f  difference:%.0f ms\n", pulsenr, dt, pc_time.utc_hour, pc_time.utc_minute, pc_time.utc_seconds, diff );
01196         pulsenr++;        
01197       }
01198       else
01199       {
01200         printf( "No ring.\n" );
01201       }
01202       c1 = clock();
01203       elapsed_time_s = ((double)(c1-c0))/((double)CLOCKS_PER_SEC);
01204     }
01205     printf( "Over 60 seconds, the difference in elapsed PC time is %.3f s\n", dt-60.0 );
01206     mean_diff/= (double)pulsenr;
01207     printf( "The mean pulse to pc time difference is: %.3f ms\n", mean_diff );
01208   }
01209 
01210 
01211   if( AllowTimeForHyperTerminalComparison )
01212   {
01213     sprintf( (char*)message, "log com%d gpzda ontime 1.0\r", SerialPortNumberOnReceiver );
01214     msg = (char*)message;
01215     SendCommand( port, msg );
01216 
01217     sprintf( (char*)message, "log com%d bestposa ontime 1.0\r", SerialPortNumberOnReceiver );
01218     msg = (char*)message;
01219     SendCommand( port, msg );
01220   }
01221 
01222   port.Close();
01223 
01224   
01225   if( AllowTimeForHyperTerminalComparison )
01226   {  
01227     printf( "The serial port is now closed you may open the port with hyperterminal for comparison.\n" );
01228     if( pps_sync_success )
01229     {
01230       count = 0;
01231       while( count < 40 )
01232       {
01233         TIMECONV_GetSystemTime(
01234           &pc_time.utc_year,
01235           &pc_time.utc_month,
01236           &pc_time.utc_day,
01237           &pc_time.utc_hour,
01238           &pc_time.utc_minute,
01239           &pc_time.utc_seconds,
01240           &pc_time.utc_offset,
01241           &pc_time.jd,
01242           &pc_time.gps_week,
01243           &pc_time.gps_tow
01244           );
01245         if( fabs(pc_time.utc_seconds - floor(pc_time.utc_seconds)) < 0.05 )
01246         {
01247           printf( "%02d:%02d:%.3f\t\t\t %d %.3f\n", pc_time.utc_hour, pc_time.utc_minute, pc_time.utc_seconds, pc_time.gps_week, pc_time.gps_tow );
01248           printf( "\a" );
01249           count++;
01250           Sleep(980);
01251         }
01252         Sleep(2);
01253       }
01254     }    
01255   }
01256 
01257   SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS );  
01258   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL );
01259 
01260   return true; 
01261 }
01262 
01263 bool SendCommand( SerialPort& port, std::string msg )
01264 {
01265   unsigned nrBytesRead = 0;
01266   if( !port.Write( (unsigned char*)msg.c_str(), msg.length() ) )
01267   {
01268     printf( "port.Write returned false.\n" );    
01269     return false;
01270   }    
01271   printf( "Command to COM%d:\n%s\n", port.GetPortNumber(), msg.c_str() );
01272   Sleep(500);
01273   return true;
01274 }
SourceForge.net Logo