📄 160
字号:
/* 12. year tens *//* 13. year units *//* 14. BST/UTC status *//* bit 7 parity *//* bit 6 always 0 *//* bit 5 always 1 *//* bit 4 always 1 *//* bit 3 always 0 *//* bit 2 =1 if UTC is in effect, complementary to the BST bit *//* bit 1 =1 if BST is in effect, according to the BST bit *//* bit 0 BST/UTC change impending bit=1 in case of change impending *//* 15. status *//* bit 7 parity *//* bit 6 always 0 *//* bit 5 always 1 *//* bit 4 always 1 *//* bit 3 =1 if low battery is detected *//* bit 2 =1 if the very last reception attempt failed and a valid *//* time information already exists (bit0=1) *//* =0 if the last reception attempt was successful *//* bit 1 =1 if at least one reception since 2:30 am was successful *//* =0 if no reception attempt since 2:30 am was successful *//* bit 0 =1 if the RC Computer Clock contains valid time information *//* This bit is zero after reset and one after the first *//* successful reception attempt *//* DHD note:Also note g<cr> command which confirms that a resync is in progress, andif so what signal quality (0--5) is available.Also note h<cr> command which starts a resync to MSF signal.*/#include <stdio.h>#include <ctype.h>#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 };/* Flags for a raw open() of the clock serial device. */#ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */#define OPEN_FLAGS (O_RDWR | O_NOCTTY)#else /* Oh well, it may not matter... */#define OPEN_FLAGS (O_RDWR)#endif/* * 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 { 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. */};#ifdef ARCRON_LEAPSECOND_KEEN /* The flag `possible_leap' is set non-zero when any MSF unit thinks a leap-second may have happened. Set whenever we receive a valid time sample in the first hour of the first day of the first/seventh months. Outside the special hour this value is unconditionally set to zero by the receive routine. On finding itself in this timeslot, as long as the value is non-negative, the receive routine sets it to a positive value to indicate a resync to MSF should be performed. In the poll routine, if this value is positive and we are not already resyncing (eg from a sync that started just before midnight), start resyncing and set this value negative to indicate that a leap-triggered resync has been started. Having set this negative prevents the receive routine setting it positive and thus prevents multiple resyncs during the witching hour. */ static int possible_leap = 0; /* No resync required by default. */#endifstatic 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;{#ifdef ARCRON_DEBUG if(debug) { printf("arc: dummy_event_handler() called.\n"); }#endif}/*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;#ifdef ARCRON_DEBUG if(debug > 2) { printf("arc: arc_event_handler() called.\n"); }#endif 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') { if(write(pp->io.fd, &c, 1) != 1) { syslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd); }#ifdef ARCRON_DEBUG else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); }#endif } 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];#ifdef HAVE_TERMIOS struct termios arg;#endif syslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit);#ifdef ARCRON_DEBUG if(debug) { printf("arc: %s: attempt to open unit %d.\n", arc_version, unit); }#endif /* 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#ifdef ARCRON_DEBUG if(debug) { printf("arc: unit %d using refclock_open().\n", unit); }#endif if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) {#ifdef DEBUG if(debug) { printf("arc: failed [TTYCLK] to open %s.\n", device); }#endif return(0); }#else#ifdef ARCRON_DEBUG if(debug) { printf("arc: unit %d using open().\n", unit); }#endif fd = open(device, OPEN_FLAGS); if(fd < 0) {#ifdef DEBUG if(debug) { printf("arc: failed [open()] to open %s.\n", device); }#endif return(0); } fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */#ifdef ARCRON_DEBUG if(debug) { printf("Opened RS232 port with file descriptor %d.\n", fd); }#endif#ifdef HAVE_TERMIOS arg.c_iflag = IGNBRK | ISTRIP; arg.c_oflag = 0; arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -