apps/sntpdate/sntpdate.c

Go to the documentation of this file.
00001 /*
00002  * Simple Network Time Protocol (SNTP) Client
00003  *
00004  * Query an NTP server for a time, and set it.
00005  * Must be run as root to actually change the system time.
00006  *
00007  * Written by Bjorn Wesen
00008  * Copyright (c) 1999, 2000 Axis Communications AB
00009  *
00010  * $Id: sntpdate.c,v 1.1.1.1 2008/11/27 20:04:01 elphel Exp $
00011  *
00012  * HISTORY
00013  * -------
00014  *
00015  * $Log: sntpdate.c,v $
00016  * Revision 1.1.1.1  2008/11/27 20:04:01  elphel
00017  *
00018  *
00019  * Revision 1.2  2008/11/21 05:38:42  elphel
00020  * forced into non-daemon mode
00021  *
00022  * Revision 1.1.1.1  2007/06/12 19:50:18  elphel
00023  * This is a fresh tree based on elphel353-2.10
00024  *
00025  * Revision 1.1.1.1  2007/06/12 19:50:18  spectr_rain
00026  * firmware for Elphel 353 cameras, based on Axis 2.10 SDK
00027  *
00028  * Revision 1.1.1.1  2007/02/23 10:11:49  elphel
00029  * initial import into CVS
00030  *
00031  * Revision 1.2  2006/07/24 07:52:26  spectr_rain
00032  * *** empty log message ***
00033  *
00034  * Revision 1.1.1.1  2006/07/11 19:15:41  spectr_rain
00035  * unwork with less than 5MPx Micron sensor, initial branch
00036  *
00037  * Revision 1.4  2006/04/28 04:16:39  spectr_rain
00038  * syncronize with NTP on gateway
00039  *
00040  * Revision 1.2  2006/01/22 22:33:06  elphel
00041  * fixed "=auto" problem (sed version in the camera seemd to work incorrectly)
00042  *
00043  * Revision 1.1  2006/01/22 20:15:08  elphel
00044  * Added/modified old Axis program
00045  *
00046  * Revision 1.14  2000/07/05 16:03:09  bjornw
00047  * Round secs correctly in set_rtc
00048  *
00049  * Revision 1.13  2000/07/05 15:45:02  bjornw
00050  * Also set the RTC time when doing big time-changes.
00051  *
00052  * Revision 1.12  2000/07/05 13:59:56  bjornw
00053  * Use adjtime instead of settimeofday for small adjustments.
00054  *
00055  * Revision 1.11  2000/07/05 09:55:55  bjornw
00056  * * gcc-cris needs long double instead of double to get 8-byte precision
00057  * * Need to cast some constants to long double to get full precision in
00058  *   some arithmetics
00059  *
00060  * Revision 1.10  2000/07/04 10:51:07  bjornw
00061  * * Now uses the full sub-second resolution timing in SNTP
00062  * * Improved logging (turned on syslog in daemon mode)
00063  * * Some indentation fixes
00064  *
00065  * Revision 1.9  2000/02/15 12:14:59  finn
00066  * main: If something went wrong in the process of either sending or receiving
00067  * an NTP message, the counter `retries' was increased by one. However, this
00068  * counter was never reset to zero between every try, hence sntpdate could
00069  * only fail five times totally.
00070  *
00071  * Revision 1.8  1999/12/15 08:21:02  torbjore
00072  * * Now uses sntpdate.conf instead of parhand for configuration
00073  *
00074  *
00075  */
00076 #include <sys/time.h>
00077 #include <time.h>
00078 #include <sys/types.h>
00079 #include <sys/stat.h>
00080 #include <fcntl.h>
00081 #include <unistd.h>
00082 #include <stdio.h>
00083 #include <stdlib.h>
00084 #include <sys/socket.h>
00085 #include <netinet/in.h>
00086 #include <arpa/inet.h>
00087 #include <string.h>
00088 #include <syslog.h>
00089 #include <netdb.h>
00090 #include <signal.h>
00091 #include <ctype.h>
00092 #include <stdarg.h>
00093 #include <errno.h>
00094 
00095 #include <asm/elphel/c313a.h>
00096 #include <asm/elphel/fpgaconfa.h>
00097 
00098 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00099   #include <asm/rtc.h>  /* for the RTC_SET_TIME ioctl */
00100 #endif  
00101 #include <sys/ioctl.h>
00102 
00103 #define NTPDATE_FILE "/etc/sntpdate.conf"
00104 #define NTPPORT 123   // NTP UDP port number
00105 #define NTPTIMEOUT 4  // retry timeout in seconds
00106 #define MAXRETRY 5    // number of times to retry
00107 
00108 #define D(x)
00109 
00110 /* some debug-output that does not require %f in vsprintf */
00111 
00112 #define D2(x)
00113 #define D3(x)
00114 
00115 /* very portable; CRIS has 4-byte doubles and 8-byte long doubles
00116  * and we need 8-byte precision...
00117  */
00118 
00119 #ifdef __CRIS__
00120 typedef long double ntp_double;
00121 #else
00122 typedef double ntp_double;
00123 #endif
00124 #define SET_FPGA_TIME 0
00125 
00126 /* NTP message format v4, from RFC 2030
00127 
00128                      1                   2                   3
00129        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00130       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00131       |LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
00132       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00133       |                          Root Delay                           |
00134       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00135       |                       Root Dispersion                         |
00136       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00137       |                     Reference Identifier                      |
00138       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00139       |                                                               |
00140       |                   Reference Timestamp (64)                    |
00141       |                                                               |
00142       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00143       |                                                               |
00144       |                   Originate Timestamp (64)                    |
00145       |                                                               |
00146       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00147       |                                                               |
00148       |                    Receive Timestamp (64)                     |
00149       |                                                               |
00150       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00151       |                                                               |
00152       |                    Transmit Timestamp (64)                    |
00153       |                                                               |
00154       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00155       |                 Key Identifier (optional) (32)                |
00156       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00157       |                                                               |
00158       |                                                               |
00159       |                 Message Digest (optional) (128)               |
00160       |                                                               |
00161       |                                                               |
00162       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00163 
00164   Size of all required fields is 48 bytes. Including optional fields, 68.
00165 
00166 */
00167 
00168 /* the NTP timestamp is the number of seconds since 0h, 1 January 1900. The
00169  * UNIX timeval started 70 years later (0h, 1 January 1970). The difference:
00170  */
00171 
00172 const unsigned long UNIX_NTP_DIFF = 2208988800U;
00173 
00174 /* it is _imperative_ that these are real 8-byte doubles otherwise nothing 
00175  * will work.
00176  */
00177 
00178 const ntp_double NTP_SCALE = 4294967296.0;            /* 2^32, of course! */
00179 const ntp_double NTP_SCALE_I = 2.3283064365e-10;      /* 2^-32 */
00180 
00181 const long MILLION_L = 1000000;          /* For conversion to/from timeval */
00182 const ntp_double MILLION_D = 1.0e6;          /* Must be equal to MILLION_L */
00183 const ntp_double MILLION_D_I = 1.0e-6;       /* Must be equal to 1 / MILLION_L */
00184 
00185 struct ntp_stamp {
00186         unsigned long sec, frac;
00187 };
00188 
00189 struct ntpmsg {
00190         unsigned long flags;
00191         unsigned long root_delay, root_dispersion, ref_id;
00192         struct ntp_stamp ref_stamp;      // time our clock was last set
00193         struct ntp_stamp orig_stamp;     // time we sent the request to the server      (T1)
00194         struct ntp_stamp receive_stamp;  // time the server received the request        (T2)
00195         struct ntp_stamp transmit_stamp; // time the server sent back the request to us (T3)
00196 };
00197 
00198 /* frac is a 32-bit binary fraction of a second
00199  * tv_usec is a 32-bit count of microseconds
00200  */
00201 
00202 #define TO_FRAC(x) ((unsigned long)((((ntp_double)x) * 1.0e-6) * NTP_SCALE))
00203 #define TO_USEC(x) ((unsigned long)((((ntp_double)x) * NTP_SCALE_I) * 1.0e6))
00204 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00205   void set_rtc(struct timeval *);
00206 #endif
00207 #define USESYSLOG 
00208 //#undef USESYSLOG 
00209 #if SET_FPGA_TIME
00210 void set_rtc_fpga(struct timeval *);
00211 #endif
00212 static int as_daemon = 0;  /* "daemon" or not. */
00213 
00214 #ifdef USESYSLOG
00215 /*
00216 **  logging support
00217 */
00218 
00219 static void
00220 log(char *str, ...)
00221 {
00222         va_list ap;
00223         static char buf[256];
00224         
00225         va_start(ap, str);
00226         vsnprintf(buf, 255, str, ap);
00227         if(as_daemon)
00228                 syslog(LOG_ERR, buf);
00229         else
00230                 fprintf(stderr, "sntpdate: %s\n", buf);
00231         va_end(ap);
00232         return;
00233 }
00234 #else
00235 #define log printf
00236 #endif
00237 
00238 static volatile int check_config = 0;
00239 
00240 static void
00241 catch_signal(int sig)
00242 {
00243         check_config = 1;
00244         signal(SIGUSR1, (void *)catch_signal);  /* retrig it */
00245 }
00246 
00247 int
00248 main(int argc, char **argv)
00249 {
00250         int ntpofd = 0;
00251         struct sockaddr_in addr;
00252         struct hostent *hp;
00253         struct ntpmsg ntpreq;
00254         struct ntpmsg ntpanswer;
00255         int retries;
00256         fd_set myset;
00257         struct timeval timeout;
00258         ntp_double T1, T2, T3, T4;
00259         ntp_double offset;
00260 //      unsigned char *ntpserver = NULL;
00261 #define MAXNUMSERVERS 10
00262         unsigned char * ntpservers[MAXNUMSERVERS];
00263         int numNTPServers=0;
00264         int curNTPServer=0;
00265         int refreshinterval = 3600;
00266         int refresh_counter = 0;
00267         int setup_connection = 0;
00268         int start_connection = 0;
00269         int zone_diff = 0;
00270         int ntp_active = 0;
00271         int use_config = 0;
00272         char* time_zone = NULL;
00273         char* time_source = NULL;
00274         int success=0;
00275    for (curNTPServer=0;curNTPServer<MAXNUMSERVERS;curNTPServer++) ntpservers[curNTPServer]=NULL;
00276 //      int i;   
00277         if(argc < 2) {
00278                 use_config = 1;
00279                 check_config = 1;
00280                 as_daemon++;
00281         }
00282         else {
00283                 if(argc == 4 && !strcmp("-d", argv[1])) {
00284                         refreshinterval = atoi(argv[2]) * 60;
00285 //                      ntpserver = argv[3];
00286                         ntpservers[numNTPServers++] = argv[3];
00287                         as_daemon++;
00288                 } else
00289 //                      ntpserver = argv[1];
00290                         ntpservers[numNTPServers++] = argv[1];
00291                 setup_connection++;
00292         }
00293 
00294 as_daemon=0;    
00295         
00296         
00297         /* set up signal handler */
00298         signal(SIGUSR1, (void *)catch_signal);
00299 
00300 #ifdef USESYSLOG
00301         /* open logfile */
00302 
00303         if (as_daemon) {
00304                 openlog(argv[0], LOG_PID, LOG_DAEMON);
00305                 syslog(LOG_INFO, "Starting sntpdate as daemon...");
00306         }
00307 #endif
00308 
00309         D(printf("Starting sntpdate as daemon...\n"));
00310         D3(printf("Starting sntpdate as daemon...\n"));
00311   
00312         /* daemon loop */
00313         if (as_daemon) {
00314                 if(fork()) {
00315                         D(printf("sntpdate started as daemon...\n"));
00316                         sleep(1);
00317                         exit(0);
00318                 }
00319         }
00320         do {
00321                 if ((check_config) && (use_config)) {
00322                         int fd;
00323                         char fdata[2048];
00324                         char* param = NULL;
00325                         char* value = NULL;
00326                         int cnt;
00327                         int cnt2;
00328                         int cnt3;
00329                         int cnt4;
00330                         int scnt;
00331                         int tcnt;
00332                         int missing = 0;
00333 
00334                         check_config = 0;
00335                         ntp_active = 0;
00336                         start_connection = 0;
00337 
00338                         fd = open (NTPDATE_FILE, O_RDONLY);
00339                         if (fd >= 0) {
00340                                 memset(fdata,0,2048);
00341                                 tcnt=read(fd,fdata,2047);
00342                                 if (tcnt==2047) {
00343                                         log("warning! conf-file too BIG!");
00344                                 }
00345                                 close(fd);
00346                                 cnt=0;
00347                                 scnt=0;
00348                                 while (scnt<tcnt) {
00349                                         while (cnt<tcnt) {
00350                                                 if ( (fdata[cnt]=='\0') ||
00351                                                      (fdata[cnt]=='\r') ||
00352                                                      (fdata[cnt]=='\n') ) {
00353                                                         fdata[cnt]='\0';
00354                                                         break;
00355                                                 }
00356                                                 D(printf("%c",fdata[cnt]));
00357                                                 cnt++;
00358                                         }
00359                                         D(printf("\n"));
00360                                         cnt2 = scnt;
00361                                         cnt4 = scnt;
00362                                         cnt3 = 0;
00363                                         while (cnt2 < cnt) {
00364                                                 if ((fdata[cnt2] == ' ')||
00365                                                     (fdata[cnt2 + 1] == '\0')) {
00366                                                         if (fdata[cnt2] == ' ') {
00367                                                                 fdata[cnt2] = '\0';
00368                                                         }
00369                                                         switch (cnt3) {
00370                                                                 case 0:
00371                                                                         param = &fdata[cnt4];
00372                                                                         break;
00373                                                                 case 1:
00374                                                                         value = &fdata[cnt4];
00375                                                                         break;
00376                                                                 default:
00377                                                                         break;
00378                                                         }
00379                                                         cnt3++;
00380                                                         cnt4 = cnt2 + 1;
00381                                                 }
00382                                                 cnt2++;
00383                                         }
00384 
00385                                         if (cnt3 == 2) {
00386                                                 D(printf("DATA=(%s)(%s)\n", param, value));
00387                                                 /* found three parts on this line */
00388                                                 if (!strncmp ("TimeZone", param, strlen ("TimeZone"))) {
00389                                                         D(printf("found TimeZone %s\n",value));
00390                                                         if (time_zone) free(time_zone);
00391                                                         time_zone = strdup(value);
00392                                                 }
00393                                                 else if (!strncmp ("TimeSyncSource", param, strlen ("TimeSyncSource"))) {
00394                                                         D(printf("found SyncSource %s\n",value));
00395                                                         if (time_source) free(time_source);
00396                                                         time_source = strdup(value);
00397                                                 }
00398                                                 else if (!strncmp ("NTPServer", param, strlen ("NTPServer"))) {
00399                                                         D(printf("found NTPServer %s\n",value));
00400 //                                                      if (ntpserver) free(ntpserver);
00401 //                                                      ntpserver = strdup(value);
00402                                                         if (numNTPServers>=MAXNUMSERVERS) printf ("Too many NTPServers (>%d) - ignoring\n",MAXNUMSERVERS);
00403                                                         else ntpservers[numNTPServers++]  = strdup(value);
00404                                                 }
00405                                                 else if (!strncmp ("NTPUpdate", param, strlen ("NTPUpdate"))) {
00406                                                         D(printf("found NTPUpdate %s\n",value));
00407                                                         refreshinterval = atoi(value);
00408                                                         if (refreshinterval == 0) {
00409                                                                 refreshinterval = 1;
00410                                                         }
00411                                                         refreshinterval *= 60;
00412                                                         D(printf("Refresh = %d\n",refreshinterval));
00413                                                 }
00414                                         }
00415                                         scnt = ++cnt;
00416                                 }
00417                                 close(fd);
00418                         }
00419                         else {
00420                                 log("error when opening config file");
00421                         }
00422 /*
00423                         if (ntpserver) {
00424                                 log("NTP server = %s", ntpserver);
00425                         }
00426 */
00427                         if (numNTPServers>0)
00428                           for (curNTPServer=0;curNTPServer<numNTPServers; curNTPServer++){
00429                                 log("NTP server #%d = %s", curNTPServer, ntpservers[curNTPServer]);
00430                         }
00431                         else
00432                                 missing++;
00433 
00434                         if (time_source) {
00435                                 if (strcmp("NTP",time_source)==0) ntp_active=1;
00436                                 log("Time Sync Source %s", time_source);
00437                         }
00438                         else
00439                                 missing++;
00440 
00441                         if (time_zone) {
00442                                 int tmp_time = 0;
00443                                 zone_diff = 0;
00444 
00445                                 D(printf("Time Zone = %s\n",time_zone));
00446                                 if (!strncmp ("NONE", time_zone, strlen ("NONE"))) {
00447                                         D(printf("No Time Zone correction!\n"));
00448                                 }
00449                                 else if (!strncmp ("GMT", time_zone, strlen ("GMT"))) {
00450                                         /* first part correct */
00451                                         if (strlen(time_zone) == 3) {
00452                                                 tmp_time = 0;
00453                                         }
00454                                         else if (time_zone[3] == '+') {
00455                                                 tmp_time = 1;
00456                                         }
00457                                         else if (time_zone[3] == '-') {
00458                                                 tmp_time = -1;
00459                                         }
00460                                         else {
00461                                                 log("Time Zone corrupt");
00462                                         }
00463 
00464                                         if (tmp_time != 0) {
00465                                                 switch (strlen(time_zone)) {
00466                                                         case 5: /* GMT-x */
00467                                                                 if (isdigit(time_zone[4])) {
00468                                                                         tmp_time*=(time_zone[4]-'0')*10;
00469                                                                 }
00470                                                                 break;
00471                                                         case 6: /* GMT-xx */
00472                                                                 if ((isdigit(time_zone[4])) &&
00473                                                                     (isdigit(time_zone[5]))) {
00474                                                                      tmp_time*=
00475                                                                       (time_zone[4]-'0')*100+(time_zone[5]-'0')*10;
00476                                                                 }
00477                                                                 break;
00478                                                         case 7: /* GMT-x.x */
00479                                                                 if ((isdigit(time_zone[4])) &&
00480                                                                     (time_zone[5]=='.') &&
00481                                                                     (isdigit(time_zone[6]))) {
00482                                                                      tmp_time*=
00483                                                                       (time_zone[4]-'0')*10+(time_zone[6]-'0');
00484                                                                 }
00485                                                                 break;
00486                                                         case 8: /* GMT-xx.x */
00487                                                                 if ((isdigit(time_zone[4])) &&
00488                                                                     (isdigit(time_zone[5])) &&
00489                                                                     (time_zone[6]=='.') &&
00490                                                                     (isdigit(time_zone[7]))) {
00491                                                                      tmp_time*=
00492                                                                       (time_zone[4]-'0')*100 +
00493                                                                       (time_zone[5]-'0')*10 +
00494                                                                       (time_zone[7]-'0');
00495                                                                 }
00496                                                                 break;
00497                                                         default: /* error */
00498                                                                 break;
00499                                                 }
00500                                         }
00501                                         zone_diff = tmp_time * 360;
00502                                         log("Zone Diff = %d", zone_diff);
00503                                 }
00504                         }
00505                         else
00506                                 missing++;
00507 
00508                         if (missing) {
00509                                 log("NTP config not complete!");
00510                                 check_config = 0;
00511                         }
00512                         else {
00513                                 setup_connection = ntp_active;
00514                                 check_config = 0;
00515                         }
00516                 }
00517                 curNTPServer=0;
00518 // moving retry loop here to try multiple servers               
00519                 retries = 0;
00520                 while(retries < MAXRETRY) {
00521 //
00522                         if (setup_connection) {
00523 //                              setup_connection = 0;
00524 
00525                                 D(printf("NTP: Setting up connection with server #%d (%s)\n",curNTPServer,ntpservers[curNTPServer]));
00526 
00527                                 /* resolve SNTP hostname */
00528 
00529 //                              if ((hp = gethostbyname(ntpserver)) == NULL) {
00530                                 if ((hp = gethostbyname(ntpservers[curNTPServer])) == NULL) {
00531 //                                      log("unknown host %s", ntpserver);
00532                                         log("unknown host %s", ntpservers[curNTPServer]);
00533                                 }
00534                                 /* setup sockets and do the connection/bind for output/input */
00535                                 else if((ntpofd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00536                                         perror("socket");
00537                                 }
00538                                 else {
00539                                         memset(&addr, 0, sizeof(addr));
00540                                         memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
00541                                         addr.sin_family = AF_INET;
00542                                         addr.sin_port   = htons(NTPPORT);
00543 
00544                                         if(connect(ntpofd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00545                                                 log("cant connect to %s", inet_ntoa(addr.sin_addr));
00546                                         }
00547                                         else {
00548                                                 start_connection = 1;
00549                                                 setup_connection = 0;
00550                                         }
00551                                 }
00552                         }
00553 
00554                         if (start_connection) {
00555                                 D(printf("NTP: Open connection\n"));
00556 
00557 //                      retries = 0;
00558 
00559                         /* create the NTP client request UDP packet */
00560 
00561                                 memset(&ntpreq, 0, sizeof(ntpreq));
00562                                 ntpreq.flags = htonl(0x23000000); // Version 4, mode 3 (client)
00563 
00564                                 /* off we go. loop if we dont get a reply */
00565 
00566 //                              while(retries < MAXRETRY) {
00567                                 struct timeval daytime;
00568 
00569                                 D(printf("sending NTP client request, retry %d\n", retries));
00570 
00571                                 /* Remember the T1 transmission time, and fill it
00572                                    into the request as well.  */
00573 
00574                                 gettimeofday(&daytime, NULL);
00575 
00576                                 T1 = (unsigned long)daytime.tv_sec + MILLION_D_I * daytime.tv_usec;
00577 
00578                                 ntpreq.transmit_stamp.sec = htonl(daytime.tv_sec + UNIX_NTP_DIFF);
00579                                 ntpreq.transmit_stamp.frac = htonl(TO_FRAC(daytime.tv_usec));
00580 
00581                                 /* send the message */
00582 
00583                                 if (send(ntpofd, &ntpreq, sizeof(ntpreq), 0) !=
00584                                     sizeof(ntpreq)) {
00585                                         log("cant send ntp request");
00586                                 }
00587 
00588                                 D2(log("transmit %u,%u  frac = %u", daytime.tv_sec, daytime.tv_usec,
00589                                        ntohl(ntpreq.transmit_stamp.frac)));
00590 
00591                                 /* and wait for the answer, using a timeout */
00592 
00593                                 timeout.tv_sec = NTPTIMEOUT;
00594                                 timeout.tv_usec = 0;
00595 
00596                                 FD_ZERO (&myset);
00597                                 FD_SET (ntpofd, &myset);
00598 
00599                                 if(select(ntpofd + 1, &myset, NULL, NULL, &timeout) > 0) {
00600 
00601                                         /* remember the T4 reception time */
00602 
00603                                         gettimeofday(&daytime, NULL);
00604 
00605                                         D2(log("receive %u,%u", daytime.tv_sec, daytime.tv_usec));
00606                                         
00607                                         T4 = (unsigned long)daytime.tv_sec + MILLION_D_I * daytime.tv_usec;
00608 
00609                                         /* read and see if its an NTP message */
00610 
00611                                         if(recv(ntpofd, &ntpanswer,
00612                                                 sizeof(ntpanswer), 0) == sizeof(ntpanswer)) {
00613                                                 D(printf("got NTP reply, flags 0x%x\n",
00614                                                          ntohl(ntpanswer.flags)));
00615                                                 break;
00616                                         }
00617                                 }
00618                         } //if (start_connection)
00619 
00620                         /* oh well. try again */
00621                         retries++;
00622                         curNTPServer++;
00623                         if (curNTPServer>=numNTPServers) curNTPServer=0; // start over
00624                         setup_connection = 1;
00625                         start_connection=0;
00626                 } // while(retries < MAXRETRY)
00627                 D(printf("broke from while(retries < MAXRETRY), retries=%d, MAXRETRY=%d\n",retries, MAXRETRY)); 
00628 // ===================== either found or too many retries =======================
00629                         if(retries == MAXRETRY) {
00630                                 log("connection attempts timed out");
00631                                 close(ntpofd);
00632                                 setup_connection = 1;
00633                         } else {
00634                                 struct timeval adjust, old, new;
00635 //                              long int zone;
00636                                 long n;
00637 
00638                                 /* process the data. extract the T2 and T3 times from the message */
00639 
00640                                 D2(log("T2 %u,%u  T3 = %u,%u", 
00641                                        ntohl(ntpanswer.receive_stamp.sec) - UNIX_NTP_DIFF,
00642                                        ntohl(ntpanswer.receive_stamp.frac),
00643                                        ntohl(ntpanswer.transmit_stamp.sec) - UNIX_NTP_DIFF,
00644                                        ntohl(ntpanswer.transmit_stamp.frac)));
00645                                 D(printf("T2 %u,%u  T3 = %u,%u", 
00646                                        ntohl(ntpanswer.receive_stamp.sec) - UNIX_NTP_DIFF,
00647                                        ntohl(ntpanswer.receive_stamp.frac),
00648                                        ntohl(ntpanswer.transmit_stamp.sec) - UNIX_NTP_DIFF,
00649                                        ntohl(ntpanswer.transmit_stamp.frac)));
00650 
00651                                 T2 = (ntohl(ntpanswer.receive_stamp.sec) - UNIX_NTP_DIFF) + 
00652                                         ((ntp_double)ntohl(ntpanswer.receive_stamp.frac)) * NTP_SCALE_I;
00653 
00654                                 T3 = (ntohl(ntpanswer.transmit_stamp.sec) - UNIX_NTP_DIFF) + 
00655                                         ((ntp_double)ntohl(ntpanswer.transmit_stamp.frac)) * NTP_SCALE_I;
00656 
00657                                 D(printf("T1 %f T2 %f T3 %f T4 %f\n", T1, T2, T3, T4));
00658 
00659                                 /* the local clock offset is a mean value of the differences */
00660 
00661                                 offset = ((T2 - T1) + (T3 - T4)) * 0.5;
00662 
00663                                 D(printf("clock offset %f\n", offset));
00664                                 D2(log("T2-T1 %d, T3-T4 %d, offset %d",
00665                                        (long)(T2-T1),
00666                                        (long)(T3-T4),
00667                                        (long)offset));
00668 
00669                                 /* compensate for zone difference between us and the server */
00670 
00671                                 offset += zone_diff;
00672 
00673                                 /* Start by converting to timeval format. Note that we have to cater for
00674                                    negative, unsigned values. */
00675                                 
00676                                 if ((n = (long)offset) > offset)
00677                                         --n;
00678                                 adjust.tv_sec = n;
00679                                 adjust.tv_usec = (long)(MILLION_D * (offset - n));
00680 
00681                                 gettimeofday(&old, NULL);
00682 
00683                                 new.tv_sec = old.tv_sec + adjust.tv_sec;
00684                                 new.tv_usec = (n = (long)old.tv_usec + (long)adjust.tv_usec);
00685 
00686                                 if (n < 0) {
00687                                         new.tv_usec += MILLION_L;
00688                                         --new.tv_sec;
00689                                 } else if (n >= MILLION_L) {
00690                                         new.tv_usec -= MILLION_L;
00691                                         ++new.tv_sec;
00692                                 }
00693 
00694                                 /* update our clock - this will only work if we're run as root! */
00695 
00696                                 if(as_daemon && ((!adjust.tv_sec && adjust.tv_usec < 131072) ||
00697                                                  (adjust.tv_sec == -1 && adjust.tv_usec > 868928))) {
00698                                         struct timeval previous;
00699                                         /* use adjtime to adjust the time - will smoothly "fade in"
00700                                          * the new time (only works for +/- 131072 usecs)
00701                                          */
00702                                         if(adjtime(&adjust, &previous)) {
00703                                                 D(printf("Unable to adjust time (%d,%d): error %m",
00704                                                     adjust.tv_sec, adjust.tv_usec, errno));
00705                                                 log("Unable to adjust time (%d,%d): error %m",
00706                                                     adjust.tv_sec, adjust.tv_usec, errno);
00707                                         } else {
00708                                                 if (previous.tv_sec || previous.tv_usec) {
00709                                                         D(printf("outstanding adjustment %u sec %u usec",
00710                                                             (long)previous.tv_sec,
00711                                                             (long)previous.tv_usec));
00712                                                         log("outstanding adjustment %u sec %u usec",
00713                                                             (long)previous.tv_sec,
00714                                                             (long)previous.tv_usec);
00715                                                 } else {
00716                                                         D(printf("adjusted %d usec",
00717                                                             adjust.tv_sec < 0 ?
00718                                                             (adjust.tv_usec - MILLION_L) :
00719                                                             adjust.tv_usec));
00720                                                         log("adjusted %d usec",
00721                                                             adjust.tv_sec < 0 ?
00722                                                             (adjust.tv_usec - MILLION_L) :
00723                                                             adjust.tv_usec);
00724                                                 }
00725                                         }
00726 
00727                                 } else {
00728                                         /* just doing it once - set it directly */
00729 
00730                                         settimeofday(&new, NULL);  /* in the kernel */
00731 #if SET_FPGA_TIME
00732                                         set_rtc_fpga(&new);             /* in the FPGA */
00733 #endif
00734 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00735                                         set_rtc(&new);             /* in the RTC through /dev/rtc */
00736 #endif
00737                                         log("set time: old=(%ld,%.6ld) new=(%ld,%.6ld) adjust=(%ld,%.6ld)",
00738                                             (long)old.tv_sec,(long)old.tv_usec,
00739                                             (long)new.tv_sec,(long)new.tv_usec,
00740                                             (long)adjust.tv_sec,(long)adjust.tv_usec);
00741                                 }
00742                                 success=1;
00743 
00744                                 //log("Date: %s", ctime((const time_t *)&new.tv_sec));
00745                         
00746                 }
00747 
00748                 /* delay "refreshinterval" seconds, but check for config update each second during
00749                  * that wait
00750                  */
00751 
00752                 if(as_daemon) {
00753                         refresh_counter = refreshinterval;
00754 
00755                         do {
00756                                 sleep(1);
00757                                 if (check_config) 
00758                                         break;
00759                         } while(refresh_counter-- > 0);
00760 
00761                         sleep(1);
00762                 }
00763 
00764         } while(as_daemon);
00765 
00766         log("Exiting...");
00767         exit(success?0:1);
00768 }
00769 
00770 /* open /dev/rtc and use an ioctl to set the time in the RTC chip */
00771 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00772 void
00773 set_rtc(struct timeval *tv)
00774 {
00775         int fd;
00776         struct tm *mytm;
00777         unsigned int secs;
00778 
00779         /* Open the rtc driver */
00780 
00781         fd = open("/dev/rtc", O_RDONLY);
00782 
00783         if(fd < 0) {
00784                 log("cant open /dev/rtc: %m", errno);
00785                 return;
00786         }
00787 
00788         /* convert from seconds since 1970 to broken down time 
00789          * (that the RTC needs)
00790          * remember to round secs depending on usecs
00791          */
00792 
00793         secs = tv->tv_sec + ((tv->tv_usec > 500000) ? 1 : 0);
00794         
00795         mytm = localtime((time_t *)&secs);
00796         
00797         /* set the RTC time
00798          * struct rtc_time is the same as struct tm
00799          */
00800 
00801         if(ioctl(fd, RTC_SET_TIME, mytm) < 0) {
00802                 log("RTC_SET_TIME failed: %m", errno);
00803         }
00804         
00805         close(fd);
00806 }
00807 #endif
00808 
00810 #if SET_FPGA_TIME
00811 #define X313_WA_RTC_USEC        0x44
00812 #define X313_WA_RTC_SEC         0x45
00813 
00814 void set_rtc_fpga(struct timeval *tv) {
00815         int fd;
00816         struct tm *mytm;
00817         unsigned int secs;
00818         unsigned long id, id_d;
00819         unsigned long tv_sec, tv_usec;
00820 
00821         if((fd = open("/dev/fpgaio", O_RDWR)) < 0)
00822                 return;
00823         id_d = ioctl(fd, _IO(FPGACONF_READREG, 0x13), (void *)&id);
00824         if((id_d & 0x0FFFF000) == 0x03331000)
00825                 if((id_d & 0x00000FFF) >= 0x0E) {
00826                         tv_sec = tv->tv_sec;
00827                         tv_usec = tv->tv_usec;
00828                         ioctl(fd, _IO(FPGACONF_WRITEREG, X313_WA_RTC_USEC), tv_usec);
00829                         ioctl(fd, _IO(FPGACONF_WRITEREG, X313_WA_RTC_SEC), tv_sec);
00830 //                      ioctl(fd, _IO(FPGACONF_WRITEREG, X313_WA_RTC_USEC), (void *)&tv_usec);
00831 //                      ioctl(fd, _IO(FPGACONF_WRITEREG, X313_WA_RTC_SEC), (void *)&tv_sec);
00832                 }
00833         close(fd);
00834 }
00835 #endif

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1