📄 144
字号:
#include <sys/time.h>#if defined(HAVE_BSD_TTYS)#include <sgtty.h>#endif /* HAVE_BSD_TTYS */#if defined(HAVE_SYSV_TTYS)#include <termio.h>#endif /* HAVE_SYSV_TTYS */#if defined(HAVE_TERMIOS)#include <termios.h>#endif#include "ntpd.h"#include "ntp_io.h"#include "ntp_refclock.h"#include "ntp_stdlib.h"/* * This driver supports the ARCRON MSF Radio Controlled Clock *//* * Interface definitions */#define DEVICE "/dev/arc%d" /* Device name and unit. */#define SPEED B300 /* UART speed (300 baud) */#define PRECISION (-4) /* Precision (~63 ms). */#define HIGHPRECISION (-5) /* If things are going well... */#define REFID "MSFa" /* Reference ID. */#define DESCRIPTION "ARCRON MSF Receiver"#define NSAMPLES 4 /* Stages of median filter. */#define NSAMPLESLONG 8 /* Stages of long filter. */#define LENARC 16 /* Format `o' timecode length. */#define BITSPERCHAR 11 /* Bits per character. */#define BITTIME 0x0DA740E /* Time for 1 bit at 300bps. */#define CHARTIME10 0x8888888 /* Time for 10-bit char at 300bps. */#define CHARTIME11 0x962FC96 /* Time for 11-bit char at 300bps. */#define CHARTIME /* Time for char at 300bps. */ \ ( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \ (BITSPERCHAR * BITTIME) ) )/* Allow for UART to accept char half-way through final stop bit. */#define INITIALOFFSET (-BITTIME/2) /* charoffsets[x] is the time after the start of the second that byte x (with the first byte being byte 1) is received by the UART, assuming that the initial edge of the start bit of the first byte is on-time. The values are represented as the fractional part of an l_fp. We store enough values to have the offset of each byte including the trailing \r, on the assumption that the bytes follow one another without gaps. */ static const u_int32 charoffsets[LENARC+1] = {#if BITSPERCHAR == 11 /* Usual case. */ /* Offsets computed as accurately as possible... */ 0, INITIALOFFSET + 0x0962fc96, /* 1 chars, 11 bits */ INITIALOFFSET + 0x12c5f92c, /* 2 chars, 22 bits */ INITIALOFFSET + 0x1c28f5c3, /* 3 chars, 33 bits */ INITIALOFFSET + 0x258bf259, /* 4 chars, 44 bits */ INITIALOFFSET + 0x2eeeeeef, /* 5 chars, 55 bits */ INITIALOFFSET + 0x3851eb85, /* 6 chars, 66 bits */ INITIALOFFSET + 0x41b4e81b, /* 7 chars, 77 bits */ INITIALOFFSET + 0x4b17e4b1, /* 8 chars, 88 bits */ INITIALOFFSET + 0x547ae148, /* 9 chars, 99 bits */ INITIALOFFSET + 0x5dddddde, /* 10 chars, 110 bits */ INITIALOFFSET + 0x6740da74, /* 11 chars, 121 bits */ INITIALOFFSET + 0x70a3d70a, /* 12 chars, 132 bits */ INITIALOFFSET + 0x7a06d3a0, /* 13 chars, 143 bits */ INITIALOFFSET + 0x8369d037, /* 14 chars, 154 bits */ INITIALOFFSET + 0x8ccccccd, /* 15 chars, 165 bits */ INITIALOFFSET + 0x962fc963 /* 16 chars, 176 bits */#else /* Offsets computed with a small rounding error... */ 0, INITIALOFFSET + 1 * CHARTIME, INITIALOFFSET + 2 * CHARTIME, INITIALOFFSET + 3 * CHARTIME, INITIALOFFSET + 4 * CHARTIME, INITIALOFFSET + 5 * CHARTIME, INITIALOFFSET + 6 * CHARTIME, INITIALOFFSET + 7 * CHARTIME, INITIALOFFSET + 8 * CHARTIME, INITIALOFFSET + 9 * CHARTIME, INITIALOFFSET + 10 * CHARTIME, INITIALOFFSET + 11 * CHARTIME, INITIALOFFSET + 12 * CHARTIME, INITIALOFFSET + 13 * CHARTIME, INITIALOFFSET + 14 * CHARTIME, INITIALOFFSET + 15 * CHARTIME, INITIALOFFSET + 16 * CHARTIME#endif };/* Chose filter length dependent on fudge flag 4. */#define CHOSENSAMPLES(pp) \ (((pp)->sloppyclockflag & CLK_FLAG4) ? NSAMPLESLONG : NSAMPLES)/*Chose how many filter samples to keep. Several factors are in play. 1) Discard at least one sample to allow a spike value to be discarded. 2) Discard about 1-in-8 to 1-in-30 samples to handle spikes. 3) Keep an odd number of samples to avoid median value being biased high or low.*/#define NKEEP(pp) ((CHOSENSAMPLES(pp) - 1 - (CHOSENSAMPLES(pp)>>3)) | 1)#define DEFAULT_RESYNC_TIME (57*60) /* Gap between resync attempts (s). */#define RETRY_RESYNC_TIME (27*60) /* Gap to emergency resync attempt. */#ifdef ARCRON_KEEN#define INITIAL_RESYNC_DELAY 500 /* Delay before first resync. */#else#define INITIAL_RESYNC_DELAY 50 /* Delay before first resync. */#endif static const int moff[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };/* * Imported from ntp_timer module */extern u_long current_time; /* Current time (s). */extern struct event timerqueue[]; /* Timer queue. *//* * Imported from ntpd module */extern int debug; /* Global debug flag. *//* Length of queue of command bytes to be sent. */#define CMDQUEUELEN 4 /* Enough for two cmds + each \r. *//* Queue tick time; interval in seconds between chars taken off queue. *//* Must be >= 2 to allow o\r response to come back uninterrupted. */#define QUEUETICK 2 /* Allow o\r reply to finish. *//* * ARC unit control structure */struct arcunit { int pollcnt; /* Poll message counter. */ l_fp lastrec; /* Time tag for the receive time (system). */ int status; /* Clock status. */ int quality; /* Quality of reception 0--5 for unit. */ /* We may also use the values -1 or 6 internally. */ u_long next_resync; /* Next resync time (s) compared to current_time. */ int resyncing; /* Resync in progress if true. */ /* In the outgoing queue, cmdqueue[0] is next to be sent. */ char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */ struct event ev; /* Event tick for sending chars. */ u_long saved_flags; /* Saved fudge flags. */};static void dummy_event_handler P((struct peer *));static void arc_event_handler P((struct peer *));#define QUALITY_UNKNOWN -1 /* Indicates unknown clock quality. */#define MIN_CLOCK_QUALITY 0 /* Min quality clock will return. */#define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */#define MAX_CLOCK_QUALITY 5 /* Max quality clock will return. *//* * Function prototypes */static int arc_start P((int, struct peer *));static void arc_shutdown P((int, struct peer *));static void arc_receive P((struct recvbuf *));static void arc_poll P((int, struct peer *));/* * Transfer vector */struct refclock refclock_arc = { arc_start, /* start up driver */ arc_shutdown, /* shut down driver */ arc_poll, /* transmit poll message */ noentry, /* not used (old arc_control) */ noentry, /* initialize driver (not used) */ noentry, /* not used (old arc_buginfo) */ NOFLAGS /* not used */};/* Queue us up for the next tick. */#define ENQUEUE(up) \ do { \ if((up)->ev.next != 0) { break; } /* WHOOPS! */ \ (up)->ev.event_time = current_time + QUEUETICK; \ TIMER_INSERT(timerqueue, &((up)->ev)); \ } while(0)/* Placeholder event handler---does nothing safely---soaks up lose tick. */static void dummy_event_handler(peer) struct peer *peer;{ if(debug) { printf("arc: dummy_event_handler() called.\n"); }}/*Normal event handler.Take first character off queue and send to clock if not a null.Shift characters down and put a null on the end.We assume that there is no parallelism so no race condition, but evenif there is nothing bad will happen except that we might send some baddata to the clock once in a while.*/static void arc_event_handler(peer) struct peer *peer;{ struct refclockproc *pp = peer->procptr; register struct arcunit *up = (struct arcunit *)pp->unitptr; int i; char c; if(debug > 2) { printf("arc: arc_event_handler() called.\n"); } c = up->cmdqueue[0]; /* Next char to be sent. */ /* Shift down characters, shifting trailing \0 in at end. */ for(i = 0; i < CMDQUEUELEN; ++i) { up->cmdqueue[i] = up->cmdqueue[i+1]; } /* Don't send '\0' characters. */ if((c != '\0') && (write(pp->io.fd, &c, 1) != 1)) { syslog(LOG_NOTICE, "ARCRON: could not write to fd %d", pp->io.fd); } if(debug && (c != '\0')) { printf("arc: sending `%2.2x' on fd %d.\n", c, pp->io.fd); } ENQUEUE(up); /* Keep ticking... */}/* * arc_start - open the devices and initialize data for processing */static intarc_start(unit, peer) int unit; struct peer *peer;{ register struct arcunit *up; struct refclockproc *pp; int fd; char device[20]; int i;#ifdef HAVE_TERMIOS struct termios arg;#endif syslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit); if(debug) { printf("arc: %s: attempt to open unit %d.\n", arc_version, unit); } /* Prevent a ridiculous device number causing overflow of device[]. */ if((unit < 0) || (unit > 255)) { return(0); } /* * Open serial port. Use CLK line discipline, if available. */ (void)sprintf(device, DEVICE, unit);#ifdef TTYCLK if(debug) { printf("arc: unit %d using refclock_open().\n", unit); } if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) { if(debug) { printf("Failed [TTYCLK] to open %s.\n", device); } return(0); }#else if(debug) { printf("arc: unit %d using open().\n", unit); } fd = open(device, O_RDWR); if(fd < 0) { if(debug) { printf("Failed [open()] to open %s.\n", device); } return(0); } fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */ if(debug) { printf("Opening RS232 port with file descriptor %d.\n", fd); }#ifdef HAVE_TERMIOS arg.c_iflag = IGNBRK | ISTRIP; arg.c_oflag = 0; arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB; arg.c_lflag = 0; arg.c_cc[VMIN] = 1; arg.c_cc[VTIME] = 0; tcsetattr(fd, TCSANOW, &arg);#else syslog(LOG_ERR, "ARCRON: termios not supported in this driver"); (void)close(fd); return 0;#endif#endif /* TTYCLK */ up = (struct arcunit *) emalloc(sizeof(struct arcunit)); if(!up) { (void) close(fd); return(0); } memset((char *)up, 0, sizeof(struct arcunit)); pp = peer->procptr; pp->io.clock_recv = arc_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; if(!io_addclock(&pp->io)) { (void) close(fd); free(up); return(0); } pp->unitptr = (caddr_t)up; /* * Initialize miscellaneous variables */ peer->precision = PRECISION; peer->stratum = 2; /* Default to stratum 2 not 0. */ pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); up->pollcnt = 2; /* Clear send buffer out... */ for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; }#ifdef ARCRON_KEEN up->quality = QUALITY_UNKNOWN; /* Trust the clock immediately. */#else up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */#endif /* Set up event structure. */ up->ev.peer = peer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -