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

Generated on Thu Aug 7 16:18:59 2008 for elphel by  doxygen 1.5.1