📄 read_psti.c
字号:
#include "ntp-config.h"#ifndef lintstatic char *rcsid = "$Header: /xtel/isode/isode/others/ntp/RCS/read_psti.c,v 9.0 1992/06/16 12:42:48 isode Rel $";static char *sccsid = "@(#)read_psti.c 1.1 MS/ACF 89/02/17";#endif lint#if defined(REFCLOCK) && defined(PSTI)#define ERR_RATE 60 /* Repeat errors once an hour *//* * read_psti.c * January 1988 -- orignal by Jeffrey I. Schiller <JIS@BITSY.MIT.EDU> * January 1989 -- QU version by Doug Kingston <DPK@Morgan.COM> * * This module facilitates reading a Precision Time Standard, Inc. * WWV radio clock. We assume that clock is configured for 9600 baud, * no parity. Output is accepted in either 24 or 12 hour format. * Time is requested and processed in GMT. * * This version is designed to make use of the QU command due to * additional information it provides (like date and flags). * Select is used to prevent hanging in a read when there are * no characters to read. The line is run in cooked mode to * reduce overhead. * * This requires a PSTI ROM revision later 4.01.000 or later. * * Routines defined: * init_clock_psti(): Open the tty associated with the clock and * set its tty mode bits. Returns fd on success * and -1 on failure. * read_clock_psti(): Reads the clock and returns either 0 on success * or non-zero on error. On success, pointers are * provided to the reference and local time. */#include <stdio.h>#include <sys/time.h>#include <sys/types.h>#include <sys/ioctl.h>#if defined(sun)#include <termio.h>#endif#ifdef DEBUGextern int debug;#endif DEBUGstatic int nerrors = 0;static char clockdata[32];#define MIN_READ 13 /* for Rev 4.01.001 */static double reltime();#ifdef STANDALONE#ifndef CLOCKDEV#define CLOCKDEV "/dev/radioclock"#endif#define DEBUG 1int debug = 1;main(argc, argv)int argc;char **argv;{ struct timeval *tvp, *otvp; debug = argc; if (openclock(CLOCKDEV)) do { (void)readclock(&tvp, &otvp); sleep(1); } while (debug>1); exit(0);}#endif STANDALONEinit_clock_psti(timesource)char *timesource;{ int cfd;#ifdef TCSETA struct termio tty;#else struct sgttyb tty;#endif if ((cfd = open(timesource, 2)) < 0) {#ifdef DEBUG if (debug) perror(timesource); else#endif DEBUG advise (LLOG_EXCEPTIONS, timesource, "can't open "); return(-1); } if (ioctl(cfd, TIOCEXCL, 0) < 0) {#ifdef DEBUG if (debug) perror("TIOCEXCL on radioclock failed"); else#endif DEBUG advise (LLOG_EXCEPTIONS, timesource, "TIOCEXCL on "); return(-1); }#ifdef TCSETA if (ioctl(cfd, TCGETA, &tty) < 0) {#ifdef DEBUG if (debug) perror("ioctl on radioclock failed"); else#endif DEBUG advise (LLOG_EXCEPTIONS, timesource, "ioctl on failed on"); return(-1); } tty.c_cflag = (B9600<<16)|B9600|CS8|CLOCAL|CREAD; tty.c_iflag = ICRNL; tty.c_oflag = 0; tty.c_lflag = 0; bzero((char *)tty.c_cc, sizeof tty.c_cc); tty.c_cc[VMIN] = MIN_READ; tty.c_cc[VTIME] = 0; if (ioctl(cfd, TCSETA, &tty) < 0) {#else TCSETA /* Use older Berkeley style IOCTL's */ bzero((char *)&tty, sizeof tty); tty.sg_ispeed = tty.sg_ospeed = B9600; tty.sg_flags = ANYP|CRMOD; tty.sg_erase = tty.sg_kill = '\0'; if (ioctl(cfd, TIOCSETP, &tty) < 0) {#endif TCSETA#ifdef DEBUG if (debug) perror("ioctl on radioclock failed"); else#endif DEBUG advise (LLOG_EXCEPTIONS, timesource, "ioctl failed on"); return(-1); } if (write(cfd, "xxxxxxsn\r", 9) != 9) {#ifdef DEBUG if (debug) perror("init write to radioclock failed"); else#endif DEBUG advise (LLOG_EXCEPTIONS, timesource, "init write to "); return(-1); } return(cfd); /* Succeeded in opening the clock */}/* * read_clock_psti() -- Read the PSTI Radio Clock. */read_clock_psti(cfd, tvpp, otvpp)int cfd;struct timeval **tvpp, **otvpp;{ static struct timeval radiotime; static struct timeval mytime; struct timeval timeout; struct tm *mtm; struct tm radio_tm, *rtm = &radio_tm; register int i; register int millis; register double diff; int stat1, stat2; fd_set readfds; char message[256];#ifndef TCSETA register char *cp; int need;#endif TCSETA FD_ZERO(&readfds); FD_SET(cfd, &readfds); timeout.tv_sec = 2; timeout.tv_usec = 0; (void) ioctl(cfd, TIOCFLUSH, 0); /* scrap the I/O queues */ /* BEGIN TIME CRITICAL CODE SECTION!!!!!! */ /* EVERY CYCLE FROM THIS POINT OUT ADDS TO THE INACCURACY OF THE READ CLOCK VALUE!!!!! */ if (write(cfd, "\003qu0000", 7) != 7) {#ifdef DEBUG if (debug) (void)printf("radioclock write failed\n"); else#endif DEBUG if ((nerrors++%ERR_RATE) == 0) advise (LLOG_EXCEPTIONS, "failed", "write to radioclock"); return(1); } if(select(cfd+1, &readfds, 0, 0, &timeout) != 1) {#ifdef DEBUG if (debug) (void)printf("radioclock poll timed out\n"); else#endif DEBUG if ((nerrors++%ERR_RATE) == 0) advise (LLOG_EXCEPTIONS, "failed", "poll of radioclock failed"); return(1); } if ((i = read(cfd, clockdata, sizeof clockdata)) < MIN_READ) {#ifdef DEBUG if (debug) (void)printf("radioclock read error (%d)\n", i); else#endif DEBUG if ((nerrors++%ERR_RATE) == 0) advise (LLOG_EXCEPTIONS, "failed", "radioclock read (%d<%d)", i, MIN_READ); return(1); } (void) gettimeofday(&mytime, (struct timezone *)0); /* END OF TIME CRITICAL CODE SECTION!!!! */ if (clockdata[i-1] != '\n') {#ifdef DEBUG if (debug) (void)printf("radioclock format error1 (%.12s)(0x%x)\n", clockdata, clockdata[12]); else#endif DEBUG if ((nerrors++%ERR_RATE) == 0) advise (LLOG_EXCEPTIONS, NULLCP, "radioclock format error1 (%.12s)(0x%x)", clockdata, clockdata[12]); return(1); } for (i = 0; i < 12; i++) { if (clockdata[i] < '0' || clockdata[i] > 'o') {#ifdef DEBUG if (debug) (void)printf("radioclock format error2\n"); else#endif DEBUG if ((nerrors++%ERR_RATE) == 0) advise (LLOG_EXCEPTIONS, NULLCP, "radioclock format error2\n"); return(1); } } stat1 = clockdata[0]-'0'; stat2 = clockdata[1]-'0'; millis = ((clockdata[2]-'0')*64)+(clockdata[3]-'0'); rtm->tm_sec = (clockdata[4]-'0'); rtm->tm_min = (clockdata[5]-'0'); rtm->tm_hour = (clockdata[6]-'0'); rtm->tm_yday = ((clockdata[7]-'0')*64)+(clockdata[8]-'0')-1; rtm->tm_year = 86+(clockdata[9]-'0'); /* byte 10 and 11 reserved */ /* * Correct "hours" based on whether or not AM/PM mode is enabled. * If clock is in 24 hour (military) mode then no correction is * needed. */ if(stat2&0x10) { /* Map AM/PM time to Military */ if (stat2&0x8) { if (rtm->tm_hour != 12) rtm->tm_hour += 12; } else { if (rtm->tm_hour == 12) rtm->tm_hour = 0; } } if (stat1 != 0x4 && (nerrors++%ERR_RATE)==0) {#ifdef DEBUG if (debug) (void)printf("radioclock fault #%d 0x%x:%s%s%s%s%s%s\n", nerrors, stat1, stat1&0x20?" Out of Spec,":"", stat1&0x10?" Hardware Fault,":"", stat1&0x8?" Signal Fault,":"", stat1&0x4?" Time Avail,":"", stat1&0x2?" Year Mismatch,":"", stat1&0x1?" Clock Reset,":""); else {#endif DEBUG (void) sprintf(message, "radioclock fault #%d 0x%x:%s%s%s%s%s%s\n", nerrors, stat1, stat1&0x20?" Out of Spec,":"", stat1&0x10?" Hardware Fault,":"", stat1&0x8?" Signal Fault,":"", stat1&0x4?" Time Avail,":"", stat1&0x2?" Year Mismatch,":"", stat1&0x1?" Clock Reset,":""); advise (LLOG_EXCEPTIONS, NULLCP, "%s", message); } } if (stat1&0x38) /* Out of Spec, Hardware Fault, Signal Fault */ return(1); if ((millis > 999 || rtm->tm_sec > 60 || rtm->tm_min > 60 || rtm->tm_hour > 23 || rtm->tm_yday > 365) && (nerrors++%ERR_RATE)==0) {#ifdef DEBUG if (debug) (void)printf("radioclock bogon #%d: %dd %dh %dm %ds %dms\n", nerrors, rtm->tm_yday, rtm->tm_hour, rtm->tm_min, rtm->tm_sec, millis); else#endif DEBUG (void) sprintf(message, "radioclock bogon #%d: %dd %dh %dm %ds %dms\n", nerrors, rtm->tm_yday, rtm->tm_hour, rtm->tm_min, rtm->tm_sec, millis); advise (LLOG_EXCEPTIONS, NULLCP, "%s", message); return(1); } mtm = gmtime(&mytime.tv_sec); diff = reltime(rtm, millis*1000) - reltime(mtm, mytime.tv_usec);#ifdef DEBUG if (debug > 1) (void) printf("Clock time: 19%d day %03d %02d:%02d:%02d.%03d diff %.3f\n", rtm->tm_year, rtm->tm_yday, rtm->tm_hour, rtm->tm_min, rtm->tm_sec, millis, diff);#endif DEBUG if (diff > (90*24*60*60.0) && (nerrors++%ERR_RATE)==0) {#ifdef DEBUG if (debug) (void) printf("offset excessive (system 19%d/%d, clock 19%d/%d)\n", mtm->tm_year, mtm->tm_yday, rtm->tm_year, mtm->tm_yday); else#endif DEBUG advise (LLOG_EXCEPTIONS, NULLCP, "offset excessive (system 19%d/%d, clock 19%d/%d)\n", mtm->tm_year, mtm->tm_yday, rtm->tm_year, mtm->tm_yday); return(1); } diff += (double)mytime.tv_sec + ((double)mytime.tv_usec/1000000.0); radiotime.tv_sec = diff; radiotime.tv_usec = (diff - (double)radiotime.tv_sec) * 1000000;#ifdef DEBUG if (debug > 1) { (void) printf("System time: 19%d day %03d %02d:%02d:%02d.%03d\n", mtm->tm_year, mtm->tm_yday, mtm->tm_hour, mtm->tm_min, mtm->tm_sec, mytime.tv_usec/1000); (void) printf("stat1 0%o, stat2 0%o: ", stat1, stat2); if (stat1 || stat2) (void) printf("%s%s%s%s%s%s%s%s%s%s%s%s", stat1&0x20?" Out of Spec,":"", stat1&0x10?" Hardware Fault,":"", stat1&0x8?" Signal Fault,":"", stat1&0x4?" Time Avail,":"", stat1&0x2?" Year Mismatch,":"", stat1&0x1?" Clock Reset,":"", stat2&0x20?" DST on,":"", stat2&0x10?" 12hr mode,":"", stat2&0x8?" PM,":"", stat2&0x4?" Spare?,":"", stat2&0x2?" DST??? +1,":"", stat2&0x1?" DST??? -1,":""); (void) printf("\n"); }#endif DEBUG /* If necessary, acknowledge "Clock Reset" flag bit */ if (stat1 & 0x1) { if (write(cfd, "si0", 3) != 3) {#ifdef DEBUG if (debug) (void)printf("radioclock reset write failed\n"); else#endif DEBUG advise (LLOG_EXCEPTIONS, "failed", "reset write to radioclock"); return(1); } } if (nerrors && stat1==0x4) { advise (LLOG_NOTICE, NULLCP, "radioclock OK (after %d errors)", nerrors); nerrors = 0; } *tvpp = &radiotime; *otvpp = &mytime; return(0);}static doublereltime(tm, usec)register struct tm *tm;register int usec;{ return(tm->tm_year*(366.0*24.0*60.0*60.0) + tm->tm_yday*(24.0*60.0*60.0) + tm->tm_hour*(60.0*60.0) + tm->tm_min*(60.0) + tm->tm_sec + usec/1000000.0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -