1: #if defined(REFCLOCK) && defined(PSTI)
   2: #ifndef lint
   3: static char *rcsid = "$Header: /usr/users/louie/ntp/RCS/read_psti.c,v 3.4.1.1 89/05/18 18:36:45 louie Exp Locker: louie $";
   4: static char *sccsid = "@(#)read_psti.c	1.1	MS/ACF	89/02/17";
   5: #endif	lint
   6: 
   7: #define ERR_RATE    60  /* Repeat errors once an hour */
   8: 
   9: /*
  10:  * read_psti.c
  11:  *     January 1988 -- orignal by Jeffrey I. Schiller <JIS@BITSY.MIT.EDU>
  12:  *     January 1989 -- QU version by Doug Kingston <DPK@Morgan.COM>
  13:  *
  14:  *   This module facilitates reading a Precision Time Standard, Inc.
  15:  *   WWV radio clock. We assume that clock is configured for 9600 baud,
  16:  *   no parity. Output is accepted in either 24 or 12 hour format.
  17:  *   Time is requested and processed in GMT.
  18:  *
  19:  *   This version is designed to make use of the QU command due to
  20:  *   additional information it provides (like date and flags).
  21:  *   Select is used to prevent hanging in a read when there are
  22:  *   no characters to read.  The line is run in cooked mode to
  23:  *   reduce overhead.
  24:  *
  25:  *   This requires a PSTI ROM revision later 4.01.000 or later.
  26:  *
  27:  *   Routines defined:
  28:  *	init_clock_psti(): Open the tty associated with the clock and
  29:  *			   set its tty mode bits. Returns fd on success
  30:  *			   and -1 on failure.
  31:  *	read_clock_psti(): Reads the clock and returns either 0 on success
  32:  *			   or non-zero on error.  On success, pointers are
  33:  *			   provided to the reference and local time.
  34:  */
  35: #include <stdio.h>
  36: #include <syslog.h>
  37: #include <sys/time.h>
  38: #include <sys/types.h>
  39: #include <sys/ioctl.h>
  40: #if defined(sun)
  41: #include <termio.h>
  42: #endif
  43: 
  44: #ifdef  DEBUG
  45: extern int debug;
  46: #endif	DEBUG
  47: 
  48: static int nerrors = 0;
  49: static char clockdata[32];
  50: #define MIN_READ 13     /* for Rev 4.01.001 */
  51: 
  52: static double reltime();
  53: 
  54: #ifdef STANDALONE
  55: 
  56: #ifndef CLOCKDEV
  57: #define CLOCKDEV "/dev/radioclock"
  58: #endif
  59: 
  60: #define DEBUG   1
  61: int debug = 1;
  62: 
  63: main(argc, argv)
  64: int argc;
  65: char **argv;
  66: {
  67:     struct timeval *tvp, *otvp;
  68: 
  69:     debug = argc;
  70:     if (openclock(CLOCKDEV))
  71:         do {
  72:             (void)readclock(&tvp, &otvp);
  73:             sleep(1);
  74:         } while (debug>1);
  75:     exit(0);
  76: }
  77: #endif STANDALONE
  78: 
  79: 
  80: init_clock_psti(timesource)
  81: char *timesource;
  82: {
  83:     int cfd;
  84: #ifdef TCSETA
  85:     struct termio tty;
  86: #else
  87:     struct sgttyb tty;
  88: #endif
  89: 
  90:     if ((cfd = open(timesource, 2)) < 0) {
  91: #ifdef DEBUG
  92:         if (debug) perror(timesource); else
  93: #endif DEBUG
  94:         syslog(LOG_ERR, "can't open %s: %m", timesource);
  95:         return(-1);
  96:     }
  97: 
  98:     if (ioctl(cfd, TIOCEXCL, 0) < 0) {
  99: #ifdef DEBUG
 100:         if (debug) perror("TIOCEXCL on radioclock failed"); else
 101: #endif DEBUG
 102:         syslog(LOG_ERR, "TIOCEXCL on %s failed: %m", timesource);
 103:         return(-1);
 104:     }
 105: 
 106: #ifdef TCSETA
 107:     if (ioctl(cfd, TCGETA, &tty) < 0) {
 108: #ifdef DEBUG
 109:         if (debug) perror("ioctl on radioclock failed"); else
 110: #endif DEBUG
 111:         syslog(LOG_ERR, "ioctl on %s failed: %m", timesource);
 112:         return(-1);
 113:     }
 114:     tty.c_cflag = (B9600<<16)|B9600|CS8|CLOCAL|CREAD;
 115:     tty.c_iflag = ICRNL;
 116:     tty.c_oflag = 0;
 117:     tty.c_lflag = 0;
 118:     bzero((char *)tty.c_cc, sizeof tty.c_cc);
 119:     tty.c_cc[VMIN] = MIN_READ;
 120:     tty.c_cc[VTIME] = 0;
 121:     if (ioctl(cfd, TCSETA, &tty) < 0) {
 122: #else TCSETA    /* Use older Berkeley style IOCTL's */
 123:     bzero((char *)&tty, sizeof tty);
 124:     tty.sg_ispeed = tty.sg_ospeed = B9600;
 125:     tty.sg_flags = ANYP|CRMOD;
 126:     tty.sg_erase = tty.sg_kill = '\0';
 127:     if (ioctl(cfd, TIOCSETP, &tty) < 0) {
 128: #endif TCSETA
 129: #ifdef DEBUG
 130:         if (debug) perror("ioctl on radioclock failed"); else
 131: #endif DEBUG
 132:         syslog(LOG_ERR, "ioctl on %s failed: %m", timesource);
 133:         return(-1);
 134:     }
 135:     if (write(cfd, "xxxxxxsn\r", 9) != 9) {
 136: #ifdef DEBUG
 137:         if (debug) perror("init write to radioclock failed"); else
 138: #endif DEBUG
 139:         syslog(LOG_ERR, "init write to %s failed: %m", timesource);
 140:         return(-1);
 141:     }
 142:     return(cfd);            /* Succeeded in opening the clock */
 143: }
 144: 
 145: /*
 146:  * read_clock_psti() -- Read the PSTI Radio Clock.
 147:  */
 148: read_clock_psti(cfd, tvpp, otvpp)
 149: int cfd;
 150: struct timeval **tvpp, **otvpp;
 151: {
 152:     static struct timeval radiotime;
 153:     static struct timeval mytime;
 154:     struct timeval timeout;
 155:     struct tm *mtm;
 156:     struct tm radio_tm, *rtm = &radio_tm;
 157:     register int i;
 158:     register int millis;
 159:     register double diff;
 160:     int stat1, stat2;
 161:     fd_set readfds;
 162:     char message[256];
 163: #ifndef TCSETA
 164:     register char *cp;
 165:     int  need;
 166: #endif TCSETA
 167: 
 168:     FD_ZERO(&readfds);
 169:     FD_SET(cfd, &readfds);
 170:     timeout.tv_sec = 2;
 171:     timeout.tv_usec = 0;
 172: 
 173:     (void) ioctl(cfd, TIOCFLUSH, 0);    /* scrap the I/O queues */
 174: 
 175:     /* BEGIN TIME CRITICAL CODE SECTION!!!!!! */
 176:     /* EVERY CYCLE FROM THIS POINT OUT ADDS TO THE INACCURACY OF
 177: 	     THE READ CLOCK VALUE!!!!! */
 178:     if (write(cfd, "\003qu0000", 7) != 7) {
 179: #ifdef DEBUG
 180:         if (debug) printf("radioclock write failed\n"); else
 181: #endif DEBUG
 182:         if ((nerrors++%ERR_RATE) == 0)
 183:             syslog(LOG_ERR, "write to radioclock failed: %m");
 184:         return(1);
 185:     }
 186:     if(select(cfd+1, &readfds, 0, 0, &timeout) != 1) {
 187: #ifdef DEBUG
 188:         if (debug) printf("radioclock poll timed out\n"); else
 189: #endif DEBUG
 190:         if ((nerrors++%ERR_RATE) == 0)
 191:             syslog(LOG_ERR, "poll of radioclock failed: %m");
 192:         return(1);
 193:     }
 194:     if ((i = read(cfd, clockdata, sizeof clockdata)) < MIN_READ) {
 195: #ifdef DEBUG
 196:         if (debug) printf("radioclock read error (%d)\n", i); else
 197: #endif DEBUG
 198:         if ((nerrors++%ERR_RATE) == 0)
 199:             syslog(LOG_ERR, "radioclock read error (%d!=13): %m", i);
 200:         return(1);
 201:     }
 202: 
 203:     (void) gettimeofday(&mytime, (struct timezone *)0);
 204:     /* END OF TIME CRITICAL CODE SECTION!!!! */
 205: 
 206:     if (clockdata[i-1] != '\n') {
 207: #ifdef DEBUG
 208:         if (debug) printf("radioclock format error1 (%.12s)(0x%x)\n",
 209:             clockdata, clockdata[12]); else
 210: #endif DEBUG
 211:         if ((nerrors++%ERR_RATE) == 0)
 212:             syslog(LOG_ERR, "radioclock format error1 (%.12s)(0x%x)",
 213:                 clockdata, clockdata[12]);
 214:         return(1);
 215:     }
 216:     for (i = 0; i < 12; i++) {
 217:         if (clockdata[i] < '0' || clockdata[i] > 'o') {
 218: #ifdef DEBUG
 219:             if (debug) printf("radioclock format error2\n"); else
 220: #endif DEBUG
 221:             if ((nerrors++%ERR_RATE) == 0)
 222:                 syslog(LOG_ERR, "radioclock format error2\n");
 223:             return(1);
 224:         }
 225:     }
 226:     stat1 = clockdata[0]-'0';
 227:     stat2 = clockdata[1]-'0';
 228:     millis = ((clockdata[2]-'0')*64)+(clockdata[3]-'0');
 229:     rtm->tm_sec = (clockdata[4]-'0');
 230:     rtm->tm_min = (clockdata[5]-'0');
 231:     rtm->tm_hour = (clockdata[6]-'0');
 232:     rtm->tm_yday = ((clockdata[7]-'0')*64)+(clockdata[8]-'0')-1;
 233:     rtm->tm_year = 86+(clockdata[9]-'0');
 234:     /* byte 10 and 11 reserved */
 235: 
 236:     /*
 237: 	 * Correct "hours" based on whether or not AM/PM mode is enabled.
 238: 	 * If clock is in 24 hour (military) mode then no correction is
 239: 	 * needed.
 240: 	 */
 241:     if(stat2&0x10) {        /* Map AM/PM time to Military */
 242:         if (stat2&0x8) {
 243:             if (rtm->tm_hour != 12) rtm->tm_hour += 12;
 244:         } else {
 245:             if (rtm->tm_hour == 12) rtm->tm_hour = 0;
 246:         }
 247:     }
 248: 
 249:     if (stat1 != 0x4 && (nerrors++%ERR_RATE)==0) {
 250: #ifdef DEBUG
 251:         if (debug) printf("radioclock fault #%d 0x%x:%s%s%s%s%s%s\n",
 252:             nerrors, stat1,
 253:             stat1&0x20?" Out of Spec,":"",
 254:             stat1&0x10?" Hardware Fault,":"",
 255:             stat1&0x8?" Signal Fault,":"",
 256:             stat1&0x4?" Time Avail,":"",
 257:             stat1&0x2?" Year Mismatch,":"",
 258:             stat1&0x1?" Clock Reset,":"");
 259:         else {
 260: #endif DEBUG
 261:             sprintf(message, "radioclock fault #%d 0x%x:%s%s%s%s%s%s\n",
 262:                 nerrors, stat1,
 263:                 stat1&0x20?" Out of Spec,":"",
 264:                 stat1&0x10?" Hardware Fault,":"",
 265:                 stat1&0x8?" Signal Fault,":"",
 266:                 stat1&0x4?" Time Avail,":"",
 267:                 stat1&0x2?" Year Mismatch,":"",
 268:                 stat1&0x1?" Clock Reset,":"");
 269:             syslog(LOG_ERR, message);
 270:         }
 271:     }
 272:     if (stat1&0x38) /* Out of Spec, Hardware Fault, Signal Fault */
 273:         return(1);
 274:     if ((millis > 999 || rtm->tm_sec > 60 || rtm->tm_min > 60 ||
 275:          rtm->tm_hour > 23 || rtm->tm_yday > 365) && (nerrors++%ERR_RATE)==0) {
 276: #ifdef DEBUG
 277:         if (debug) printf("radioclock bogon #%d: %dd %dh %dm %ds %dms\n",
 278:             nerrors, rtm->tm_yday, rtm->tm_hour,
 279:             rtm->tm_min, rtm->tm_sec, millis);
 280:         else
 281: #endif DEBUG
 282:         sprintf(message, "radioclock bogon #%d: %dd %dh %dm %ds %dms\n",
 283:             nerrors, rtm->tm_yday, rtm->tm_hour,
 284:             rtm->tm_min, rtm->tm_sec, millis);
 285:         syslog(LOG_ERR, message);
 286:         return(1);
 287:     }
 288: 
 289:     mtm = gmtime(&mytime.tv_sec);
 290:     diff =  reltime(rtm, millis*1000) - reltime(mtm, mytime.tv_usec);
 291: #ifdef DEBUG
 292:     if (debug > 1)
 293:         printf("Clock time:  19%d day %03d %02d:%02d:%02d.%03d diff %.3f\n",
 294:             rtm->tm_year, rtm->tm_yday, rtm->tm_hour,
 295:             rtm->tm_min, rtm->tm_sec, millis, diff);
 296: #endif DEBUG
 297: 
 298:     if (diff > (90*24*60*60.0) && (nerrors++%ERR_RATE)==0) {
 299: #ifdef DEBUG
 300:         if (debug)
 301:             printf("offset excessive (system 19%d/%d, clock 19%d/%d)\n",
 302:                 mtm->tm_year, mtm->tm_yday,
 303:                 rtm->tm_year, mtm->tm_yday);
 304:         else
 305: #endif DEBUG
 306:         syslog(LOG_ERR, "offset excessive (system 19%d/%d, clock 19%d/%d)\n",
 307:                 mtm->tm_year, mtm->tm_yday,
 308:                 rtm->tm_year, mtm->tm_yday);
 309:         return(1);
 310:     }
 311: 
 312:     diff += (double)mytime.tv_sec + ((double)mytime.tv_usec/1000000.0);
 313:     radiotime.tv_sec = diff;
 314:     radiotime.tv_usec = (diff - (double)radiotime.tv_sec) * 1000000;
 315: #ifdef DEBUG
 316:     if (debug > 1) {
 317:         printf("System time: 19%d day %03d %02d:%02d:%02d.%03d\n",
 318:             mtm->tm_year, mtm->tm_yday, mtm->tm_hour,
 319:             mtm->tm_min, mtm->tm_sec, mytime.tv_usec/1000);
 320:         printf("stat1 0%o, stat2 0%o: ", stat1, stat2);
 321:         if (stat1 || stat2)
 322:             printf("%s%s%s%s%s%s%s%s%s%s%s%s",
 323:                 stat1&0x20?" Out of Spec,":"",
 324:                 stat1&0x10?" Hardware Fault,":"",
 325:                 stat1&0x8?" Signal Fault,":"",
 326:                 stat1&0x4?" Time Avail,":"",
 327:                 stat1&0x2?" Year Mismatch,":"",
 328:                 stat1&0x1?" Clock Reset,":"",
 329:                 stat2&0x20?" DST on,":"",
 330:                 stat2&0x10?" 12hr mode,":"",
 331:                 stat2&0x8?" PM,":"",
 332:                 stat2&0x4?" Spare?,":"",
 333:                 stat2&0x2?" DST??? +1,":"",
 334:                 stat2&0x1?" DST??? -1,":"");
 335:         printf("\n");
 336:     }
 337: #endif DEBUG
 338:     /* If necessary, acknowledge "Clock Reset" flag bit */
 339:     if (stat1 & 0x1) {
 340:         if (write(cfd, "si0", 3) != 3) {
 341: #ifdef DEBUG
 342:             if (debug) printf("radioclock reset write failed\n"); else
 343: #endif DEBUG
 344:             syslog(LOG_ERR, "reset write to radioclock failed: %m");
 345:             return(1);
 346:         }
 347:     }
 348:     if (nerrors && stat1==0x4) {
 349:         syslog(LOG_ERR, "radioclock OK (after %d errors)", nerrors);
 350:         nerrors = 0;
 351:     }
 352:     *tvpp = &radiotime;
 353:     *otvpp = &mytime;
 354:     return(0);
 355: }
 356: 
 357: static double
 358: reltime(tm, usec)
 359: register struct tm *tm;
 360: register int usec;
 361: {
 362:     return(tm->tm_year*(366.0*24.0*60.0*60.0) +
 363:            tm->tm_yday*(24.0*60.0*60.0) +
 364:            tm->tm_hour*(60.0*60.0) +
 365:            tm->tm_min*(60.0) +
 366:            tm->tm_sec +
 367:            usec/1000000.0);
 368: }
 369: #endif

Defined functions

init_clock_psti defined in line 80; used 2 times
main defined in line 63; never used
read_clock_psti defined in line 148; used 2 times
reltime defined in line 357; used 3 times

Defined variables

clockdata defined in line 49; used 19 times
debug declared in line 45; defined in line 61; used 69 times
nerrors defined in line 48; used 15 times
rcsid defined in line 3; never used
sccsid defined in line 4; never used

Defined macros

CLOCKDEV defined in line 57; used 2 times
DEBUG defined in line 60; used 17 times
ERR_RATE defined in line 7; used 8 times
MIN_READ defined in line 50; used 2 times
Last modified: 1989-05-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4326
Valid CSS Valid XHTML 1.0 Strict