1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert ** refclock_datum - clock driver for the Datum Programmable Time Server 3c0b746e5SOllivier Robert ** 4c0b746e5SOllivier Robert ** Important note: This driver assumes that you have termios. If you have 5c0b746e5SOllivier Robert ** a system that does not have termios, you will have to modify this driver. 6c0b746e5SOllivier Robert ** 7c0b746e5SOllivier Robert ** Sorry, I have only tested this driver on SUN and HP platforms. 8c0b746e5SOllivier Robert */ 9c0b746e5SOllivier Robert 10c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 11c0b746e5SOllivier Robert # include <config.h> 12c0b746e5SOllivier Robert #endif 13c0b746e5SOllivier Robert 14c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_DATUM) 15c0b746e5SOllivier Robert 16c0b746e5SOllivier Robert /* 17c0b746e5SOllivier Robert ** Include Files 18c0b746e5SOllivier Robert */ 19c0b746e5SOllivier Robert 20c0b746e5SOllivier Robert #include "ntpd.h" 21c0b746e5SOllivier Robert #include "ntp_io.h" 22c0b746e5SOllivier Robert #include "ntp_refclock.h" 23c0b746e5SOllivier Robert #include "ntp_unixtime.h" 24c0b746e5SOllivier Robert #include "ntp_stdlib.h" 25c0b746e5SOllivier Robert 26224ba2bdSOllivier Robert #include <stdio.h> 27224ba2bdSOllivier Robert #include <ctype.h> 28224ba2bdSOllivier Robert 29c0b746e5SOllivier Robert #if defined(HAVE_BSD_TTYS) 30c0b746e5SOllivier Robert #include <sgtty.h> 31c0b746e5SOllivier Robert #endif /* HAVE_BSD_TTYS */ 32c0b746e5SOllivier Robert 33c0b746e5SOllivier Robert #if defined(HAVE_SYSV_TTYS) 34c0b746e5SOllivier Robert #include <termio.h> 35c0b746e5SOllivier Robert #endif /* HAVE_SYSV_TTYS */ 36c0b746e5SOllivier Robert 37c0b746e5SOllivier Robert #if defined(HAVE_TERMIOS) 38c0b746e5SOllivier Robert #include <termios.h> 39c0b746e5SOllivier Robert #endif 40c0b746e5SOllivier Robert #if defined(STREAM) 41c0b746e5SOllivier Robert #include <stropts.h> 42c0b746e5SOllivier Robert #if defined(WWVBCLK) 43c0b746e5SOllivier Robert #include <sys/clkdefs.h> 44c0b746e5SOllivier Robert #endif /* WWVBCLK */ 45c0b746e5SOllivier Robert #endif /* STREAM */ 46c0b746e5SOllivier Robert 47c0b746e5SOllivier Robert #include "ntp_stdlib.h" 48c0b746e5SOllivier Robert 49c0b746e5SOllivier Robert /* 50c0b746e5SOllivier Robert ** This driver supports the Datum Programmable Time System (PTS) clock. 51c0b746e5SOllivier Robert ** The clock works in very straight forward manner. When it receives a 52c0b746e5SOllivier Robert ** time code request (e.g., the ascii string "//k/mn"), it responds with 53c0b746e5SOllivier Robert ** a seven byte BCD time code. This clock only responds with a 54c0b746e5SOllivier Robert ** time code after it first receives the "//k/mn" message. It does not 55c0b746e5SOllivier Robert ** periodically send time codes back at some rate once it is started. 56c0b746e5SOllivier Robert ** the returned time code can be broken down into the following fields. 57c0b746e5SOllivier Robert ** 58c0b746e5SOllivier Robert ** _______________________________ 59c0b746e5SOllivier Robert ** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 60c0b746e5SOllivier Robert ** =============================== 61c0b746e5SOllivier Robert ** byte 0: | - - - - | H D | 62c0b746e5SOllivier Robert ** =============================== 63c0b746e5SOllivier Robert ** byte 1: | T D | U D | 64c0b746e5SOllivier Robert ** =============================== 65c0b746e5SOllivier Robert ** byte 2: | - - | T H | U H | 66c0b746e5SOllivier Robert ** =============================== 67c0b746e5SOllivier Robert ** byte 3: | - | T M | U M | 68c0b746e5SOllivier Robert ** =============================== 69c0b746e5SOllivier Robert ** byte 4: | - | T S | U S | 70c0b746e5SOllivier Robert ** =============================== 71c0b746e5SOllivier Robert ** byte 5: | t S | h S | 72c0b746e5SOllivier Robert ** =============================== 73c0b746e5SOllivier Robert ** byte 6: | m S | - - - - | 74c0b746e5SOllivier Robert ** =============================== 75c0b746e5SOllivier Robert ** 76c0b746e5SOllivier Robert ** In the table above: 77c0b746e5SOllivier Robert ** 78c0b746e5SOllivier Robert ** "-" means don't care 79c0b746e5SOllivier Robert ** "H D", "T D", and "U D" means Hundreds, Tens, and Units of Days 80c0b746e5SOllivier Robert ** "T H", and "UH" means Tens and Units of Hours 81c0b746e5SOllivier Robert ** "T M", and "U M" means Tens and Units of Minutes 82c0b746e5SOllivier Robert ** "T S", and "U S" means Tens and Units of Seconds 83c0b746e5SOllivier Robert ** "t S", "h S", and "m S" means tenths, hundredths, and thousandths 84c0b746e5SOllivier Robert ** of seconds 85c0b746e5SOllivier Robert ** 86c0b746e5SOllivier Robert ** The Datum PTS communicates throught the RS232 port on your machine. 87c0b746e5SOllivier Robert ** Right now, it assumes that you have termios. This driver has been tested 88c0b746e5SOllivier Robert ** on SUN and HP workstations. The Datum PTS supports various IRIG and 89c0b746e5SOllivier Robert ** NASA input codes. This driver assumes that the name of the device is 90c0b746e5SOllivier Robert ** /dev/datum. You will need to make a soft link to your RS232 device or 91c0b746e5SOllivier Robert ** create a new driver to use this refclock. 92c0b746e5SOllivier Robert */ 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert /* 95c0b746e5SOllivier Robert ** Datum PTS defines 96c0b746e5SOllivier Robert */ 97c0b746e5SOllivier Robert 98c0b746e5SOllivier Robert /* 99c0b746e5SOllivier Robert ** Note that if GMT is defined, then the Datum PTS must use Greenwich 100c0b746e5SOllivier Robert ** time. Otherwise, this driver allows the Datum PTS to use the current 101c0b746e5SOllivier Robert ** wall clock for its time. It determines the time zone offset by minimizing 102c0b746e5SOllivier Robert ** the error after trying several time zone offsets. If the Datum PTS 103c0b746e5SOllivier Robert ** time is Greenwich time and GMT is not defined, everything should still 104c0b746e5SOllivier Robert ** work since the time zone will be found to be 0. What this really means 105c0b746e5SOllivier Robert ** is that your system time (at least to start with) must be within the 106c0b746e5SOllivier Robert ** correct time by less than +- 30 minutes. The default is for GMT to not 107c0b746e5SOllivier Robert ** defined. If you really want to force GMT without the funny +- 30 minute 108c0b746e5SOllivier Robert ** stuff then you must define (uncomment) GMT below. 109c0b746e5SOllivier Robert */ 110c0b746e5SOllivier Robert 111c0b746e5SOllivier Robert /* 112c0b746e5SOllivier Robert #define GMT 113c0b746e5SOllivier Robert #define DEBUG_DATUM_PTC 114c0b746e5SOllivier Robert #define LOG_TIME_ERRORS 115c0b746e5SOllivier Robert */ 116c0b746e5SOllivier Robert 117c0b746e5SOllivier Robert 118224ba2bdSOllivier Robert #define PRECISION (-10) /* precision assumed 1/1024 ms */ 119224ba2bdSOllivier Robert #define REFID "DATM" /* reference id */ 120c0b746e5SOllivier Robert #define DATUM_DISPERSION 0 /* fixed dispersion = 0 ms */ 121c0b746e5SOllivier Robert #define DATUM_MAX_ERROR 0.100 /* limits on sigma squared */ 122ea906c41SOllivier Robert #define DATUM_DEV "/dev/datum" /* device name */ 123c0b746e5SOllivier Robert 124c0b746e5SOllivier Robert #define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR) 125c0b746e5SOllivier Robert 126c0b746e5SOllivier Robert /* 127c0b746e5SOllivier Robert ** The Datum PTS structure 128c0b746e5SOllivier Robert */ 129c0b746e5SOllivier Robert 130c0b746e5SOllivier Robert /* 131c0b746e5SOllivier Robert ** I don't use a fixed array of MAXUNITS like everyone else just because 132c0b746e5SOllivier Robert ** I don't like to program that way. Sorry if this bothers anyone. I assume 133c0b746e5SOllivier Robert ** that you can use any id for your unit and I will search for it in a 134c0b746e5SOllivier Robert ** dynamic array of units until I find it. I was worried that users might 135c0b746e5SOllivier Robert ** enter a bad id in their configuration file (larger than MAXUNITS) and 136c0b746e5SOllivier Robert ** besides, it is just cleaner not to have to assume that you have a fixed 137c0b746e5SOllivier Robert ** number of anything in a program. 138c0b746e5SOllivier Robert */ 139c0b746e5SOllivier Robert 140c0b746e5SOllivier Robert struct datum_pts_unit { 141c0b746e5SOllivier Robert struct peer *peer; /* peer used by ntp */ 142c0b746e5SOllivier Robert struct refclockio io; /* io structure used by ntp */ 143c0b746e5SOllivier Robert int PTS_fd; /* file descriptor for PTS */ 144c0b746e5SOllivier Robert u_int unit; /* id for unit */ 145c0b746e5SOllivier Robert u_long timestarted; /* time started */ 146c0b746e5SOllivier Robert l_fp lastrec; /* time tag for the receive time (system) */ 147c0b746e5SOllivier Robert l_fp lastref; /* reference time (Datum time) */ 148c0b746e5SOllivier Robert u_long yearstart; /* the year that this clock started */ 149c0b746e5SOllivier Robert int coderecv; /* number of time codes received */ 150c0b746e5SOllivier Robert int day; /* day */ 151c0b746e5SOllivier Robert int hour; /* hour */ 152c0b746e5SOllivier Robert int minute; /* minutes */ 153c0b746e5SOllivier Robert int second; /* seconds */ 154c0b746e5SOllivier Robert int msec; /* miliseconds */ 155c0b746e5SOllivier Robert int usec; /* miliseconds */ 156c0b746e5SOllivier Robert u_char leap; /* funny leap character code */ 157c0b746e5SOllivier Robert char retbuf[8]; /* returned time from the datum pts */ 158c0b746e5SOllivier Robert char nbytes; /* number of bytes received from datum pts */ 159c0b746e5SOllivier Robert double sigma2; /* average squared error (roughly) */ 160c0b746e5SOllivier Robert int tzoff; /* time zone offest from GMT */ 161c0b746e5SOllivier Robert }; 162c0b746e5SOllivier Robert 163c0b746e5SOllivier Robert /* 164c0b746e5SOllivier Robert ** PTS static constant variables for internal use 165c0b746e5SOllivier Robert */ 166c0b746e5SOllivier Robert 167c0b746e5SOllivier Robert static char TIME_REQUEST[6]; /* request message sent to datum for time */ 168c0b746e5SOllivier Robert static int nunits; /* number of active units */ 169c0b746e5SOllivier Robert static struct datum_pts_unit 170c0b746e5SOllivier Robert **datum_pts_unit; /* dynamic array of datum PTS structures */ 171c0b746e5SOllivier Robert 172c0b746e5SOllivier Robert /* 173c0b746e5SOllivier Robert ** Callback function prototypes that ntpd needs to know about. 174c0b746e5SOllivier Robert */ 175c0b746e5SOllivier Robert 176c0b746e5SOllivier Robert static int datum_pts_start P((int, struct peer *)); 177c0b746e5SOllivier Robert static void datum_pts_shutdown P((int, struct peer *)); 178c0b746e5SOllivier Robert static void datum_pts_poll P((int, struct peer *)); 179c0b746e5SOllivier Robert static void datum_pts_control P((int, struct refclockstat *, 180c0b746e5SOllivier Robert struct refclockstat *, struct peer *)); 181c0b746e5SOllivier Robert static void datum_pts_init P((void)); 182c0b746e5SOllivier Robert static void datum_pts_buginfo P((int, struct refclockbug *, struct peer *)); 183c0b746e5SOllivier Robert 184c0b746e5SOllivier Robert /* 185c0b746e5SOllivier Robert ** This is the call back function structure that ntpd actually uses for 186c0b746e5SOllivier Robert ** this refclock. 187c0b746e5SOllivier Robert */ 188c0b746e5SOllivier Robert 189c0b746e5SOllivier Robert struct refclock refclock_datum = { 190c0b746e5SOllivier Robert datum_pts_start, /* start up a new Datum refclock */ 191c0b746e5SOllivier Robert datum_pts_shutdown, /* shutdown a Datum refclock */ 192c0b746e5SOllivier Robert datum_pts_poll, /* sends out the time request */ 193c0b746e5SOllivier Robert datum_pts_control, /* not used */ 194c0b746e5SOllivier Robert datum_pts_init, /* initialization (called first) */ 195c0b746e5SOllivier Robert datum_pts_buginfo, /* not used */ 196c0b746e5SOllivier Robert NOFLAGS /* we are not setting any special flags */ 197c0b746e5SOllivier Robert }; 198c0b746e5SOllivier Robert 199c0b746e5SOllivier Robert /* 200c0b746e5SOllivier Robert ** The datum_pts_receive callback function is handled differently from the 201c0b746e5SOllivier Robert ** rest. It is passed to the ntpd io data structure. Basically, every 202c0b746e5SOllivier Robert ** 64 seconds, the datum_pts_poll() routine is called. It sends out the time 203c0b746e5SOllivier Robert ** request message to the Datum Programmable Time System. Then, ntpd 204c0b746e5SOllivier Robert ** waits on a select() call to receive data back. The datum_pts_receive() 205c0b746e5SOllivier Robert ** function is called as data comes back. We expect a seven byte time 206c0b746e5SOllivier Robert ** code to be returned but the datum_pts_receive() function may only get 207c0b746e5SOllivier Robert ** a few bytes passed to it at a time. In other words, this routine may 208c0b746e5SOllivier Robert ** get called by the io stuff in ntpd a few times before we get all seven 209c0b746e5SOllivier Robert ** bytes. Once the last byte is received, we process it and then pass the 210c0b746e5SOllivier Robert ** new time measurement to ntpd for updating the system time. For now, 211c0b746e5SOllivier Robert ** there is no 3 state filtering done on the time measurements. The 212c0b746e5SOllivier Robert ** jitter may be a little high but at least for its current use, it is not 213c0b746e5SOllivier Robert ** a problem. We have tried to keep things as simple as possible. This 214c0b746e5SOllivier Robert ** clock should not jitter more than 1 or 2 mseconds at the most once 215c0b746e5SOllivier Robert ** things settle down. It is important to get the right drift calibrated 216c0b746e5SOllivier Robert ** in the ntpd.drift file as well as getting the right tick set up right 217c0b746e5SOllivier Robert ** using tickadj for SUNs. Tickadj is not used for the HP but you need to 218c0b746e5SOllivier Robert ** remember to bring up the adjtime daemon because HP does not support 219c0b746e5SOllivier Robert ** the adjtime() call. 220c0b746e5SOllivier Robert */ 221c0b746e5SOllivier Robert 222c0b746e5SOllivier Robert static void datum_pts_receive P((struct recvbuf *)); 223c0b746e5SOllivier Robert 224c0b746e5SOllivier Robert /*......................................................................*/ 225c0b746e5SOllivier Robert /* datum_pts_start - start up the datum PTS. This means open the */ 226c0b746e5SOllivier Robert /* RS232 device and set up the data structure for my unit. */ 227c0b746e5SOllivier Robert /*......................................................................*/ 228c0b746e5SOllivier Robert 229c0b746e5SOllivier Robert static int 230c0b746e5SOllivier Robert datum_pts_start( 231c0b746e5SOllivier Robert int unit, 232c0b746e5SOllivier Robert struct peer *peer 233c0b746e5SOllivier Robert ) 234c0b746e5SOllivier Robert { 235c0b746e5SOllivier Robert struct datum_pts_unit **temp_datum_pts_unit; 236c0b746e5SOllivier Robert struct datum_pts_unit *datum_pts; 237ea906c41SOllivier Robert int fd; 238c0b746e5SOllivier Robert #ifdef HAVE_TERMIOS 239c0b746e5SOllivier Robert struct termios arg; 240c0b746e5SOllivier Robert #endif 241c0b746e5SOllivier Robert 242c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 243c0b746e5SOllivier Robert if (debug) 244c0b746e5SOllivier Robert printf("Starting Datum PTS unit %d\n", unit); 245c0b746e5SOllivier Robert #endif 246c0b746e5SOllivier Robert 247c0b746e5SOllivier Robert /* 248ea906c41SOllivier Robert ** Open the Datum PTS device 249ea906c41SOllivier Robert */ 250ea906c41SOllivier Robert fd = open(DATUM_DEV, O_RDWR); 251ea906c41SOllivier Robert 252ea906c41SOllivier Robert if (fd < 0) { 253ea906c41SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: open(\"%s\", O_RDWR) failed: %m", DATUM_DEV); 254ea906c41SOllivier Robert return 0; 255ea906c41SOllivier Robert } 256ea906c41SOllivier Robert 257ea906c41SOllivier Robert /* 258c0b746e5SOllivier Robert ** Create the memory for the new unit 259c0b746e5SOllivier Robert */ 260c0b746e5SOllivier Robert 261c0b746e5SOllivier Robert temp_datum_pts_unit = (struct datum_pts_unit **) 262c0b746e5SOllivier Robert malloc((nunits+1)*sizeof(struct datum_pts_unit *)); 263c0b746e5SOllivier Robert if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit, 264c0b746e5SOllivier Robert nunits*sizeof(struct datum_pts_unit *)); 265c0b746e5SOllivier Robert free(datum_pts_unit); 266c0b746e5SOllivier Robert datum_pts_unit = temp_datum_pts_unit; 267c0b746e5SOllivier Robert datum_pts_unit[nunits] = (struct datum_pts_unit *) 268c0b746e5SOllivier Robert malloc(sizeof(struct datum_pts_unit)); 269c0b746e5SOllivier Robert datum_pts = datum_pts_unit[nunits]; 270c0b746e5SOllivier Robert 271c0b746e5SOllivier Robert datum_pts->unit = unit; /* set my unit id */ 272c0b746e5SOllivier Robert datum_pts->yearstart = 0; /* initialize the yearstart to 0 */ 273c0b746e5SOllivier Robert datum_pts->sigma2 = 0.0; /* initialize the sigma2 to 0 */ 274c0b746e5SOllivier Robert 275ea906c41SOllivier Robert datum_pts->PTS_fd = fd; 276c0b746e5SOllivier Robert 277c0b746e5SOllivier Robert fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */ 278c0b746e5SOllivier Robert 279c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 280c0b746e5SOllivier Robert if (debug) 281c0b746e5SOllivier Robert printf("Opening RS232 port with file descriptor %d\n", 282c0b746e5SOllivier Robert datum_pts->PTS_fd); 283c0b746e5SOllivier Robert #endif 284c0b746e5SOllivier Robert 285c0b746e5SOllivier Robert /* 286c0b746e5SOllivier Robert ** Set up the RS232 terminal device information. Note that we assume that 287c0b746e5SOllivier Robert ** we have termios. This code has only been tested on SUNs and HPs. If your 288c0b746e5SOllivier Robert ** machine does not have termios this driver cannot be initialized. You can change this 289c0b746e5SOllivier Robert ** if you want by editing this source. Please give the changes back to the 290c0b746e5SOllivier Robert ** ntp folks so that it can become part of their regular distribution. 291c0b746e5SOllivier Robert */ 292c0b746e5SOllivier Robert 293c0b746e5SOllivier Robert #ifdef HAVE_TERMIOS 294c0b746e5SOllivier Robert 295c0b746e5SOllivier Robert arg.c_iflag = IGNBRK; 296c0b746e5SOllivier Robert arg.c_oflag = 0; 297c0b746e5SOllivier Robert arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL; 298c0b746e5SOllivier Robert arg.c_lflag = 0; 299c0b746e5SOllivier Robert arg.c_cc[VMIN] = 0; /* start timeout timer right away (not used) */ 300c0b746e5SOllivier Robert arg.c_cc[VTIME] = 30; /* 3 second timout on reads (not used) */ 301c0b746e5SOllivier Robert 302c0b746e5SOllivier Robert tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg); 303c0b746e5SOllivier Robert 304c0b746e5SOllivier Robert #else 305c0b746e5SOllivier Robert 306c0b746e5SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver"); 307c0b746e5SOllivier Robert (void)close(datum_pts->PTS_fd); 308c0b746e5SOllivier Robert 309224ba2bdSOllivier Robert peer->precision = PRECISION; 310224ba2bdSOllivier Robert pp->clockdesc = DESCRIPTION; 311224ba2bdSOllivier Robert memcpy((char *)&pp->refid, REFID, 4); 312224ba2bdSOllivier Robert 313c0b746e5SOllivier Robert return 0; 314c0b746e5SOllivier Robert 315c0b746e5SOllivier Robert #endif 316c0b746e5SOllivier Robert 317c0b746e5SOllivier Robert /* 318c0b746e5SOllivier Robert ** Initialize the ntpd IO structure 319c0b746e5SOllivier Robert */ 320c0b746e5SOllivier Robert 321c0b746e5SOllivier Robert datum_pts->peer = peer; 322c0b746e5SOllivier Robert datum_pts->io.clock_recv = datum_pts_receive; 323c0b746e5SOllivier Robert datum_pts->io.srcclock = (caddr_t)datum_pts; 324c0b746e5SOllivier Robert datum_pts->io.datalen = 0; 325c0b746e5SOllivier Robert datum_pts->io.fd = datum_pts->PTS_fd; 326c0b746e5SOllivier Robert 327c0b746e5SOllivier Robert if (!io_addclock(&(datum_pts->io))) { 328c0b746e5SOllivier Robert 329c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 330c0b746e5SOllivier Robert if (debug) 331c0b746e5SOllivier Robert printf("Problem adding clock\n"); 332c0b746e5SOllivier Robert #endif 333c0b746e5SOllivier Robert 334c0b746e5SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: Problem adding clock"); 335c0b746e5SOllivier Robert (void)close(datum_pts->PTS_fd); 336c0b746e5SOllivier Robert 337c0b746e5SOllivier Robert return 0; 338c0b746e5SOllivier Robert } 339c0b746e5SOllivier Robert 340c0b746e5SOllivier Robert /* 341c0b746e5SOllivier Robert ** Now add one to the number of units and return a successful code 342c0b746e5SOllivier Robert */ 343c0b746e5SOllivier Robert 344c0b746e5SOllivier Robert nunits++; 345c0b746e5SOllivier Robert return 1; 346c0b746e5SOllivier Robert 347c0b746e5SOllivier Robert } 348c0b746e5SOllivier Robert 349c0b746e5SOllivier Robert 350c0b746e5SOllivier Robert /*......................................................................*/ 351c0b746e5SOllivier Robert /* datum_pts_shutdown - this routine shuts doen the device and */ 352c0b746e5SOllivier Robert /* removes the memory for the unit. */ 353c0b746e5SOllivier Robert /*......................................................................*/ 354c0b746e5SOllivier Robert 355c0b746e5SOllivier Robert static void 356c0b746e5SOllivier Robert datum_pts_shutdown( 357c0b746e5SOllivier Robert int unit, 358c0b746e5SOllivier Robert struct peer *peer 359c0b746e5SOllivier Robert ) 360c0b746e5SOllivier Robert { 361c0b746e5SOllivier Robert int i,j; 362c0b746e5SOllivier Robert struct datum_pts_unit **temp_datum_pts_unit; 363c0b746e5SOllivier Robert 364c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 365c0b746e5SOllivier Robert if (debug) 366c0b746e5SOllivier Robert printf("Shutdown Datum PTS\n"); 367c0b746e5SOllivier Robert #endif 368c0b746e5SOllivier Robert 369c0b746e5SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS"); 370c0b746e5SOllivier Robert 371c0b746e5SOllivier Robert /* 372c0b746e5SOllivier Robert ** First we have to find the right unit (i.e., the one with the same id). 373c0b746e5SOllivier Robert ** We do this by looping through the dynamic array of units intil we find 374c0b746e5SOllivier Robert ** it. Note, that I don't simply use an array with a maximimum number of 375c0b746e5SOllivier Robert ** Datum PTS units. Everything is completely dynamic. 376c0b746e5SOllivier Robert */ 377c0b746e5SOllivier Robert 378c0b746e5SOllivier Robert for (i=0; i<nunits; i++) { 379c0b746e5SOllivier Robert if (datum_pts_unit[i]->unit == unit) { 380c0b746e5SOllivier Robert 381c0b746e5SOllivier Robert /* 382c0b746e5SOllivier Robert ** We found the unit so close the file descriptor and free up the memory used 383c0b746e5SOllivier Robert ** by the structure. 384c0b746e5SOllivier Robert */ 385c0b746e5SOllivier Robert 386c0b746e5SOllivier Robert io_closeclock(&datum_pts_unit[i]->io); 387c0b746e5SOllivier Robert close(datum_pts_unit[i]->PTS_fd); 388c0b746e5SOllivier Robert free(datum_pts_unit[i]); 389c0b746e5SOllivier Robert 390c0b746e5SOllivier Robert /* 391c0b746e5SOllivier Robert ** Now clean up the datum_pts_unit dynamic array so that there are no holes. 392c0b746e5SOllivier Robert ** This may mean moving pointers around, etc., to keep things compact. 393c0b746e5SOllivier Robert */ 394c0b746e5SOllivier Robert 395c0b746e5SOllivier Robert if (nunits > 1) { 396c0b746e5SOllivier Robert 397c0b746e5SOllivier Robert temp_datum_pts_unit = (struct datum_pts_unit **) 398c0b746e5SOllivier Robert malloc((nunits-1)*sizeof(struct datum_pts_unit *)); 399c0b746e5SOllivier Robert if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit, 400c0b746e5SOllivier Robert i*sizeof(struct datum_pts_unit *)); 401c0b746e5SOllivier Robert 402c0b746e5SOllivier Robert for (j=i+1; j<nunits; j++) { 403c0b746e5SOllivier Robert temp_datum_pts_unit[j-1] = datum_pts_unit[j]; 404c0b746e5SOllivier Robert } 405c0b746e5SOllivier Robert 406c0b746e5SOllivier Robert free(datum_pts_unit); 407c0b746e5SOllivier Robert datum_pts_unit = temp_datum_pts_unit; 408c0b746e5SOllivier Robert 409c0b746e5SOllivier Robert }else{ 410c0b746e5SOllivier Robert 411c0b746e5SOllivier Robert free(datum_pts_unit); 412c0b746e5SOllivier Robert datum_pts_unit = NULL; 413c0b746e5SOllivier Robert 414c0b746e5SOllivier Robert } 415c0b746e5SOllivier Robert 416c0b746e5SOllivier Robert return; 417c0b746e5SOllivier Robert 418c0b746e5SOllivier Robert } 419c0b746e5SOllivier Robert } 420c0b746e5SOllivier Robert 421c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 422c0b746e5SOllivier Robert if (debug) 423c0b746e5SOllivier Robert printf("Error, could not shut down unit %d\n",unit); 424c0b746e5SOllivier Robert #endif 425c0b746e5SOllivier Robert 426c0b746e5SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit); 427c0b746e5SOllivier Robert 428c0b746e5SOllivier Robert } 429c0b746e5SOllivier Robert 430c0b746e5SOllivier Robert /*......................................................................*/ 431c0b746e5SOllivier Robert /* datum_pts_poll - this routine sends out the time request to the */ 432c0b746e5SOllivier Robert /* Datum PTS device. The time will be passed back in the */ 433c0b746e5SOllivier Robert /* datum_pts_receive() routine. */ 434c0b746e5SOllivier Robert /*......................................................................*/ 435c0b746e5SOllivier Robert 436c0b746e5SOllivier Robert static void 437c0b746e5SOllivier Robert datum_pts_poll( 438c0b746e5SOllivier Robert int unit, 439c0b746e5SOllivier Robert struct peer *peer 440c0b746e5SOllivier Robert ) 441c0b746e5SOllivier Robert { 442c0b746e5SOllivier Robert int i; 443224ba2bdSOllivier Robert int unit_index; 444c0b746e5SOllivier Robert int error_code; 445c0b746e5SOllivier Robert struct datum_pts_unit *datum_pts; 446c0b746e5SOllivier Robert 447c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 448c0b746e5SOllivier Robert if (debug) 449c0b746e5SOllivier Robert printf("Poll Datum PTS\n"); 450c0b746e5SOllivier Robert #endif 451c0b746e5SOllivier Robert 452c0b746e5SOllivier Robert /* 453c0b746e5SOllivier Robert ** Find the right unit and send out a time request once it is found. 454c0b746e5SOllivier Robert */ 455c0b746e5SOllivier Robert 456224ba2bdSOllivier Robert unit_index = -1; 457c0b746e5SOllivier Robert for (i=0; i<nunits; i++) { 458c0b746e5SOllivier Robert if (datum_pts_unit[i]->unit == unit) { 459224ba2bdSOllivier Robert unit_index = i; 460c0b746e5SOllivier Robert datum_pts = datum_pts_unit[i]; 461c0b746e5SOllivier Robert error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6); 462c0b746e5SOllivier Robert if (error_code != 6) perror("TIME_REQUEST"); 463c0b746e5SOllivier Robert datum_pts->nbytes = 0; 464c0b746e5SOllivier Robert break; 465c0b746e5SOllivier Robert } 466c0b746e5SOllivier Robert } 467c0b746e5SOllivier Robert 468c0b746e5SOllivier Robert /* 469c0b746e5SOllivier Robert ** Print out an error message if we could not find the right unit. 470c0b746e5SOllivier Robert */ 471c0b746e5SOllivier Robert 472224ba2bdSOllivier Robert if (unit_index == -1) { 473c0b746e5SOllivier Robert 474c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 475c0b746e5SOllivier Robert if (debug) 476c0b746e5SOllivier Robert printf("Error, could not poll unit %d\n",unit); 477c0b746e5SOllivier Robert #endif 478c0b746e5SOllivier Robert 479c0b746e5SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit); 480c0b746e5SOllivier Robert return; 481c0b746e5SOllivier Robert 482c0b746e5SOllivier Robert } 483c0b746e5SOllivier Robert 484c0b746e5SOllivier Robert } 485c0b746e5SOllivier Robert 486c0b746e5SOllivier Robert 487c0b746e5SOllivier Robert /*......................................................................*/ 488c0b746e5SOllivier Robert /* datum_pts_control - not used */ 489c0b746e5SOllivier Robert /*......................................................................*/ 490c0b746e5SOllivier Robert 491c0b746e5SOllivier Robert static void 492c0b746e5SOllivier Robert datum_pts_control( 493c0b746e5SOllivier Robert int unit, 494c0b746e5SOllivier Robert struct refclockstat *in, 495c0b746e5SOllivier Robert struct refclockstat *out, 496c0b746e5SOllivier Robert struct peer *peer 497c0b746e5SOllivier Robert ) 498c0b746e5SOllivier Robert { 499c0b746e5SOllivier Robert 500c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 501c0b746e5SOllivier Robert if (debug) 502c0b746e5SOllivier Robert printf("Control Datum PTS\n"); 503c0b746e5SOllivier Robert #endif 504c0b746e5SOllivier Robert 505c0b746e5SOllivier Robert } 506c0b746e5SOllivier Robert 507c0b746e5SOllivier Robert 508c0b746e5SOllivier Robert /*......................................................................*/ 509c0b746e5SOllivier Robert /* datum_pts_init - initializes things for all possible Datum */ 510c0b746e5SOllivier Robert /* time code generators that might be used. In practice, this is */ 511c0b746e5SOllivier Robert /* only called once at the beginning before anything else is */ 512c0b746e5SOllivier Robert /* called. */ 513c0b746e5SOllivier Robert /*......................................................................*/ 514c0b746e5SOllivier Robert 515c0b746e5SOllivier Robert static void 516c0b746e5SOllivier Robert datum_pts_init(void) 517c0b746e5SOllivier Robert { 518c0b746e5SOllivier Robert 519c0b746e5SOllivier Robert /* */ 520c0b746e5SOllivier Robert /*...... open up the log file if we are debugging ......................*/ 521c0b746e5SOllivier Robert /* */ 522c0b746e5SOllivier Robert 523c0b746e5SOllivier Robert /* 524c0b746e5SOllivier Robert ** Open up the log file if we are debugging. For now, send data out to the 525c0b746e5SOllivier Robert ** screen (stdout). 526c0b746e5SOllivier Robert */ 527c0b746e5SOllivier Robert 528c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 529c0b746e5SOllivier Robert if (debug) 530c0b746e5SOllivier Robert printf("Init Datum PTS\n"); 531c0b746e5SOllivier Robert #endif 532c0b746e5SOllivier Robert 533c0b746e5SOllivier Robert /* 534c0b746e5SOllivier Robert ** Initialize the time request command string. This is the only message 535c0b746e5SOllivier Robert ** that we ever have to send to the Datum PTS (although others are defined). 536c0b746e5SOllivier Robert */ 537c0b746e5SOllivier Robert 538c0b746e5SOllivier Robert memcpy(TIME_REQUEST, "//k/mn",6); 539c0b746e5SOllivier Robert 540c0b746e5SOllivier Robert /* 541c0b746e5SOllivier Robert ** Initialize the number of units to 0 and set the dynamic array of units to 542c0b746e5SOllivier Robert ** NULL since there are no units defined yet. 543c0b746e5SOllivier Robert */ 544c0b746e5SOllivier Robert 545c0b746e5SOllivier Robert datum_pts_unit = NULL; 546c0b746e5SOllivier Robert nunits = 0; 547c0b746e5SOllivier Robert 548c0b746e5SOllivier Robert } 549c0b746e5SOllivier Robert 550c0b746e5SOllivier Robert 551c0b746e5SOllivier Robert /*......................................................................*/ 552c0b746e5SOllivier Robert /* datum_pts_buginfo - not used */ 553c0b746e5SOllivier Robert /*......................................................................*/ 554c0b746e5SOllivier Robert 555c0b746e5SOllivier Robert static void 556c0b746e5SOllivier Robert datum_pts_buginfo( 557c0b746e5SOllivier Robert int unit, 558c0b746e5SOllivier Robert register struct refclockbug *bug, 559c0b746e5SOllivier Robert register struct peer *peer 560c0b746e5SOllivier Robert ) 561c0b746e5SOllivier Robert { 562c0b746e5SOllivier Robert 563c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 564c0b746e5SOllivier Robert if (debug) 565c0b746e5SOllivier Robert printf("Buginfo Datum PTS\n"); 566c0b746e5SOllivier Robert #endif 567c0b746e5SOllivier Robert 568c0b746e5SOllivier Robert } 569c0b746e5SOllivier Robert 570c0b746e5SOllivier Robert 571c0b746e5SOllivier Robert /*......................................................................*/ 572c0b746e5SOllivier Robert /* datum_pts_receive - receive the time buffer that was read in */ 573c0b746e5SOllivier Robert /* by the ntpd io handling routines. When 7 bytes have been */ 574c0b746e5SOllivier Robert /* received (it may take several tries before all 7 bytes are */ 575c0b746e5SOllivier Robert /* received), then the time code must be unpacked and sent to */ 576c0b746e5SOllivier Robert /* the ntpd clock_receive() routine which causes the systems */ 577c0b746e5SOllivier Robert /* clock to be updated (several layers down). */ 578c0b746e5SOllivier Robert /*......................................................................*/ 579c0b746e5SOllivier Robert 580c0b746e5SOllivier Robert static void 581c0b746e5SOllivier Robert datum_pts_receive( 582c0b746e5SOllivier Robert struct recvbuf *rbufp 583c0b746e5SOllivier Robert ) 584c0b746e5SOllivier Robert { 585c0b746e5SOllivier Robert int i; 586c0b746e5SOllivier Robert l_fp tstmp; 587c0b746e5SOllivier Robert struct datum_pts_unit *datum_pts; 588c0b746e5SOllivier Robert char *dpt; 589c0b746e5SOllivier Robert int dpend; 590c0b746e5SOllivier Robert int tzoff; 591c0b746e5SOllivier Robert int timerr; 592c0b746e5SOllivier Robert double ftimerr, abserr; 593c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 594c0b746e5SOllivier Robert double dispersion; 595c0b746e5SOllivier Robert #endif 596c0b746e5SOllivier Robert int goodtime; 597c0b746e5SOllivier Robert /*double doffset;*/ 598c0b746e5SOllivier Robert 599c0b746e5SOllivier Robert /* 600c0b746e5SOllivier Robert ** Get the time code (maybe partial) message out of the rbufp buffer. 601c0b746e5SOllivier Robert */ 602c0b746e5SOllivier Robert 603c0b746e5SOllivier Robert datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock; 604c0b746e5SOllivier Robert dpt = (char *)&rbufp->recv_space; 605c0b746e5SOllivier Robert dpend = rbufp->recv_length; 606c0b746e5SOllivier Robert 607c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 608c0b746e5SOllivier Robert if (debug) 609c0b746e5SOllivier Robert printf("Receive Datum PTS: %d bytes\n", dpend); 610c0b746e5SOllivier Robert #endif 611c0b746e5SOllivier Robert 612c0b746e5SOllivier Robert /* */ 613c0b746e5SOllivier Robert /*...... save the ntp system time when the first byte is received ......*/ 614c0b746e5SOllivier Robert /* */ 615c0b746e5SOllivier Robert 616c0b746e5SOllivier Robert /* 617c0b746e5SOllivier Robert ** Save the ntp system time when the first byte is received. Note that 618c0b746e5SOllivier Robert ** because it may take several calls to this routine before all seven 619c0b746e5SOllivier Robert ** bytes of our return message are finally received by the io handlers in 620c0b746e5SOllivier Robert ** ntpd, we really do want to use the time tag when the first byte is 621c0b746e5SOllivier Robert ** received to reduce the jitter. 622c0b746e5SOllivier Robert */ 623c0b746e5SOllivier Robert 624c0b746e5SOllivier Robert if (datum_pts->nbytes == 0) { 625c0b746e5SOllivier Robert datum_pts->lastrec = rbufp->recv_time; 626c0b746e5SOllivier Robert } 627c0b746e5SOllivier Robert 628c0b746e5SOllivier Robert /* 629c0b746e5SOllivier Robert ** Increment our count to the number of bytes received so far. Return if we 630c0b746e5SOllivier Robert ** haven't gotten all seven bytes yet. 631c0b746e5SOllivier Robert */ 632c0b746e5SOllivier Robert 633c0b746e5SOllivier Robert for (i=0; i<dpend; i++) { 634c0b746e5SOllivier Robert datum_pts->retbuf[datum_pts->nbytes+i] = dpt[i]; 635c0b746e5SOllivier Robert } 636c0b746e5SOllivier Robert 637c0b746e5SOllivier Robert datum_pts->nbytes += dpend; 638c0b746e5SOllivier Robert 639c0b746e5SOllivier Robert if (datum_pts->nbytes != 7) { 640c0b746e5SOllivier Robert return; 641c0b746e5SOllivier Robert } 642c0b746e5SOllivier Robert 643c0b746e5SOllivier Robert /* 644c0b746e5SOllivier Robert ** Convert the seven bytes received in our time buffer to day, hour, minute, 645c0b746e5SOllivier Robert ** second, and msecond values. The usec value is not used for anything 646c0b746e5SOllivier Robert ** currently. It is just the fractional part of the time stored in units 647c0b746e5SOllivier Robert ** of microseconds. 648c0b746e5SOllivier Robert */ 649c0b746e5SOllivier Robert 650c0b746e5SOllivier Robert datum_pts->day = 100*(datum_pts->retbuf[0] & 0x0f) + 651c0b746e5SOllivier Robert 10*((datum_pts->retbuf[1] & 0xf0)>>4) + 652c0b746e5SOllivier Robert (datum_pts->retbuf[1] & 0x0f); 653c0b746e5SOllivier Robert 654c0b746e5SOllivier Robert datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) + 655c0b746e5SOllivier Robert (datum_pts->retbuf[2] & 0x0f); 656c0b746e5SOllivier Robert 657c0b746e5SOllivier Robert datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) + 658c0b746e5SOllivier Robert (datum_pts->retbuf[3] & 0x0f); 659c0b746e5SOllivier Robert 660c0b746e5SOllivier Robert datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) + 661c0b746e5SOllivier Robert (datum_pts->retbuf[4] & 0x0f); 662c0b746e5SOllivier Robert 663c0b746e5SOllivier Robert datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) + 664c0b746e5SOllivier Robert 10*(datum_pts->retbuf[5] & 0x0f) + 665c0b746e5SOllivier Robert ((datum_pts->retbuf[6] & 0xf0)>>4); 666c0b746e5SOllivier Robert 667c0b746e5SOllivier Robert datum_pts->usec = 1000*datum_pts->msec; 668c0b746e5SOllivier Robert 669c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 670c0b746e5SOllivier Robert if (debug) 671c0b746e5SOllivier Robert printf("day %d, hour %d, minute %d, second %d, msec %d\n", 672c0b746e5SOllivier Robert datum_pts->day, 673c0b746e5SOllivier Robert datum_pts->hour, 674c0b746e5SOllivier Robert datum_pts->minute, 675c0b746e5SOllivier Robert datum_pts->second, 676c0b746e5SOllivier Robert datum_pts->msec); 677c0b746e5SOllivier Robert #endif 678c0b746e5SOllivier Robert 679c0b746e5SOllivier Robert /* 680c0b746e5SOllivier Robert ** Get the GMT time zone offset. Note that GMT should be zero if the Datum 681c0b746e5SOllivier Robert ** reference time is using GMT as its time base. Otherwise we have to 682c0b746e5SOllivier Robert ** determine the offset if the Datum PTS is using time of day as its time 683c0b746e5SOllivier Robert ** base. 684c0b746e5SOllivier Robert */ 685c0b746e5SOllivier Robert 686c0b746e5SOllivier Robert goodtime = 0; /* We are not sure about the time and offset yet */ 687c0b746e5SOllivier Robert 688c0b746e5SOllivier Robert #ifdef GMT 689c0b746e5SOllivier Robert 690c0b746e5SOllivier Robert /* 691c0b746e5SOllivier Robert ** This is the case where the Datum PTS is using GMT so there is no time 692c0b746e5SOllivier Robert ** zone offset. 693c0b746e5SOllivier Robert */ 694c0b746e5SOllivier Robert 695c0b746e5SOllivier Robert tzoff = 0; /* set time zone offset to 0 */ 696c0b746e5SOllivier Robert 697c0b746e5SOllivier Robert #else 698c0b746e5SOllivier Robert 699c0b746e5SOllivier Robert /* 700c0b746e5SOllivier Robert ** This is the case where the Datum PTS is using regular time of day for its 701c0b746e5SOllivier Robert ** time so we must compute the time zone offset. The way we do it is kind of 702c0b746e5SOllivier Robert ** funny but it works. We loop through different time zones (0 to 24) and 703c0b746e5SOllivier Robert ** pick the one that gives the smallest error (+- one half hour). The time 704c0b746e5SOllivier Robert ** zone offset is stored in the datum_pts structure for future use. Normally, 705c0b746e5SOllivier Robert ** the clocktime() routine is only called once (unless the time zone offset 706c0b746e5SOllivier Robert ** changes due to daylight savings) since the goodtime flag is set when a 707c0b746e5SOllivier Robert ** good time is found (with a good offset). Note that even if the Datum 708c0b746e5SOllivier Robert ** PTS is using GMT, this mechanism will still work since it should come up 709c0b746e5SOllivier Robert ** with a value for tzoff = 0 (assuming that your system clock is within 710c0b746e5SOllivier Robert ** a half hour of the Datum time (even with time zone differences). 711c0b746e5SOllivier Robert */ 712c0b746e5SOllivier Robert 713c0b746e5SOllivier Robert for (tzoff=0; tzoff<24; tzoff++) { 714c0b746e5SOllivier Robert if (clocktime( datum_pts->day, 715c0b746e5SOllivier Robert datum_pts->hour, 716c0b746e5SOllivier Robert datum_pts->minute, 717c0b746e5SOllivier Robert datum_pts->second, 718c0b746e5SOllivier Robert (tzoff + datum_pts->tzoff) % 24, 719c0b746e5SOllivier Robert datum_pts->lastrec.l_ui, 720c0b746e5SOllivier Robert &datum_pts->yearstart, 721c0b746e5SOllivier Robert &datum_pts->lastref.l_ui) ) { 722c0b746e5SOllivier Robert 7239c2daa00SOllivier Robert datum_pts->lastref.l_uf = 0; 724c0b746e5SOllivier Robert error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui; 725c0b746e5SOllivier Robert 726c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 727c0b746e5SOllivier Robert printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error); 728c0b746e5SOllivier Robert #endif 729c0b746e5SOllivier Robert 730c0b746e5SOllivier Robert if ((error < 1799) && (error > -1799)) { 731c0b746e5SOllivier Robert tzoff = (tzoff + datum_pts->tzoff) % 24; 732c0b746e5SOllivier Robert datum_pts->tzoff = tzoff; 733c0b746e5SOllivier Robert goodtime = 1; 734c0b746e5SOllivier Robert 735c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 736c0b746e5SOllivier Robert printf("Time Zone found (clocktime method) = %d\n",tzoff); 737c0b746e5SOllivier Robert #endif 738c0b746e5SOllivier Robert 739c0b746e5SOllivier Robert break; 740c0b746e5SOllivier Robert } 741c0b746e5SOllivier Robert 742c0b746e5SOllivier Robert } 743c0b746e5SOllivier Robert } 744c0b746e5SOllivier Robert 745c0b746e5SOllivier Robert #endif 746c0b746e5SOllivier Robert 747c0b746e5SOllivier Robert /* 748c0b746e5SOllivier Robert ** Make sure that we have a good time from the Datum PTS. Clocktime() also 749c0b746e5SOllivier Robert ** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e., 750c0b746e5SOllivier Robert ** the fraction of a second) stuff later. 751c0b746e5SOllivier Robert */ 752c0b746e5SOllivier Robert 753c0b746e5SOllivier Robert if (!goodtime) { 754c0b746e5SOllivier Robert 755c0b746e5SOllivier Robert if (!clocktime( datum_pts->day, 756c0b746e5SOllivier Robert datum_pts->hour, 757c0b746e5SOllivier Robert datum_pts->minute, 758c0b746e5SOllivier Robert datum_pts->second, 759c0b746e5SOllivier Robert tzoff, 760c0b746e5SOllivier Robert datum_pts->lastrec.l_ui, 761c0b746e5SOllivier Robert &datum_pts->yearstart, 762c0b746e5SOllivier Robert &datum_pts->lastref.l_ui) ) { 763c0b746e5SOllivier Robert 764c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 765c0b746e5SOllivier Robert if (debug) 766c0b746e5SOllivier Robert { 767c0b746e5SOllivier Robert printf("Error: bad clocktime\n"); 768c0b746e5SOllivier Robert printf("GMT %d, lastrec %d, yearstart %d, lastref %d\n", 769c0b746e5SOllivier Robert tzoff, 770c0b746e5SOllivier Robert datum_pts->lastrec.l_ui, 771c0b746e5SOllivier Robert datum_pts->yearstart, 772c0b746e5SOllivier Robert datum_pts->lastref.l_ui); 773c0b746e5SOllivier Robert } 774c0b746e5SOllivier Robert #endif 775c0b746e5SOllivier Robert 776c0b746e5SOllivier Robert msyslog(LOG_ERR, "Datum_PTS: Bad clocktime"); 777c0b746e5SOllivier Robert 778c0b746e5SOllivier Robert return; 779c0b746e5SOllivier Robert 780c0b746e5SOllivier Robert }else{ 781c0b746e5SOllivier Robert 782c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 783c0b746e5SOllivier Robert if (debug) 784c0b746e5SOllivier Robert printf("Good clocktime\n"); 785c0b746e5SOllivier Robert #endif 786c0b746e5SOllivier Robert 787c0b746e5SOllivier Robert } 788c0b746e5SOllivier Robert 789c0b746e5SOllivier Robert } 790c0b746e5SOllivier Robert 791c0b746e5SOllivier Robert /* 792c0b746e5SOllivier Robert ** We have datum_pts->lastref.l_ui set (which is the integer part of the 793c0b746e5SOllivier Robert ** time. Now set the microseconds field. 794c0b746e5SOllivier Robert */ 795c0b746e5SOllivier Robert 796c0b746e5SOllivier Robert TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf); 797c0b746e5SOllivier Robert 798c0b746e5SOllivier Robert /* 799c0b746e5SOllivier Robert ** Compute the time correction as the difference between the reference 800c0b746e5SOllivier Robert ** time (i.e., the Datum time) minus the receive time (system time). 801c0b746e5SOllivier Robert */ 802c0b746e5SOllivier Robert 803c0b746e5SOllivier Robert tstmp = datum_pts->lastref; /* tstmp is the datum ntp time */ 804c0b746e5SOllivier Robert L_SUB(&tstmp, &datum_pts->lastrec); /* tstmp is now the correction */ 805c0b746e5SOllivier Robert datum_pts->coderecv++; /* increment a counter */ 806c0b746e5SOllivier Robert 807c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 808c0b746e5SOllivier Robert dispersion = DATUM_DISPERSION; /* set the dispersion to 0 */ 809c0b746e5SOllivier Robert ftimerr = dispersion; 810c0b746e5SOllivier Robert ftimerr /= (1024.0 * 64.0); 811c0b746e5SOllivier Robert if (debug) 812c0b746e5SOllivier Robert printf("dispersion = %d, %f\n", dispersion, ftimerr); 813c0b746e5SOllivier Robert #endif 814c0b746e5SOllivier Robert 815c0b746e5SOllivier Robert /* 816c0b746e5SOllivier Robert ** Pass the new time to ntpd through the refclock_receive function. Note 817c0b746e5SOllivier Robert ** that we are not trying to make any corrections due to the time it takes 818c0b746e5SOllivier Robert ** for the Datum PTS to send the message back. I am (erroneously) assuming 819c0b746e5SOllivier Robert ** that the time for the Datum PTS to send the time back to us is negligable. 820c0b746e5SOllivier Robert ** I suspect that this time delay may be as much as 15 ms or so (but probably 821c0b746e5SOllivier Robert ** less). For our needs at JPL, this kind of error is ok so it is not 822c0b746e5SOllivier Robert ** necessary to use fudge factors in the ntp.conf file. Maybe later we will. 823c0b746e5SOllivier Robert */ 824c0b746e5SOllivier Robert /*LFPTOD(&tstmp, doffset);*/ 8259c2daa00SOllivier Robert datum_pts->lastref = datum_pts->lastrec; 826c0b746e5SOllivier Robert refclock_receive(datum_pts->peer); 827c0b746e5SOllivier Robert 828c0b746e5SOllivier Robert /* 829c0b746e5SOllivier Robert ** Compute sigma squared (not used currently). Maybe later, this could be 830c0b746e5SOllivier Robert ** used for the dispersion estimate. The problem is that ntpd does not link 831c0b746e5SOllivier Robert ** in the math library so sqrt() is not available. Anyway, this is useful 832c0b746e5SOllivier Robert ** for debugging. Maybe later I will just use absolute values for the time 833c0b746e5SOllivier Robert ** error to come up with my dispersion estimate. Anyway, for now my dispersion 834c0b746e5SOllivier Robert ** is set to 0. 835c0b746e5SOllivier Robert */ 836c0b746e5SOllivier Robert 837c0b746e5SOllivier Robert timerr = tstmp.l_ui<<20; 838c0b746e5SOllivier Robert timerr |= (tstmp.l_uf>>12) & 0x000fffff; 839c0b746e5SOllivier Robert ftimerr = timerr; 840c0b746e5SOllivier Robert ftimerr /= 1024*1024; 841c0b746e5SOllivier Robert abserr = ftimerr; 842c0b746e5SOllivier Robert if (ftimerr < 0.0) abserr = -ftimerr; 843c0b746e5SOllivier Robert 844c0b746e5SOllivier Robert if (datum_pts->sigma2 == 0.0) { 845c0b746e5SOllivier Robert if (abserr < DATUM_MAX_ERROR) { 846c0b746e5SOllivier Robert datum_pts->sigma2 = abserr*abserr; 847c0b746e5SOllivier Robert }else{ 848c0b746e5SOllivier Robert datum_pts->sigma2 = DATUM_MAX_ERROR2; 849c0b746e5SOllivier Robert } 850c0b746e5SOllivier Robert }else{ 851c0b746e5SOllivier Robert if (abserr < DATUM_MAX_ERROR) { 852c0b746e5SOllivier Robert datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr; 853c0b746e5SOllivier Robert }else{ 854c0b746e5SOllivier Robert datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2; 855c0b746e5SOllivier Robert } 856c0b746e5SOllivier Robert } 857c0b746e5SOllivier Robert 858c0b746e5SOllivier Robert #ifdef DEBUG_DATUM_PTC 859c0b746e5SOllivier Robert if (debug) 860c0b746e5SOllivier Robert printf("Time error = %f seconds\n", ftimerr); 861c0b746e5SOllivier Robert #endif 862c0b746e5SOllivier Robert 863c0b746e5SOllivier Robert #if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS) 864c0b746e5SOllivier Robert if (debug) 865c0b746e5SOllivier Robert printf("PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n", 866c0b746e5SOllivier Robert datum_pts->day, 867c0b746e5SOllivier Robert datum_pts->hour, 868c0b746e5SOllivier Robert datum_pts->minute, 869c0b746e5SOllivier Robert datum_pts->second, 870c0b746e5SOllivier Robert datum_pts->msec, 871c0b746e5SOllivier Robert ftimerr); 872c0b746e5SOllivier Robert #endif 873c0b746e5SOllivier Robert 874c0b746e5SOllivier Robert } 875c0b746e5SOllivier Robert #else 876c0b746e5SOllivier Robert int refclock_datum_bs; 877c0b746e5SOllivier Robert #endif /* REFCLOCK */ 878