?? refclock_arc.c
字號:
#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 (u_int32)(-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 };#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/* 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 quality_stamp; /* Next time to reset quality average. */ 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. */ 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. */#endif#if 0static void dummy_event_handler P((struct peer *));static void arc_event_handler P((struct peer *));#endif /* 0 */#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 { \ peer->nextaction = current_time + QUEUETICK; \ } while(0)/* Placeholder event handler---does nothing safely---soaks up loose tick. */static voiddummy_event_handler( struct peer *peer ){#ifdef 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 voidarc_event_handler( struct peer *peer ){ struct refclockproc *pp = peer->procptr; register struct arcunit *up = (struct arcunit *)pp->unitptr; int i; char c;#ifdef 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) { msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd); }#ifdef DEBUG else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); }#endif } ENQUEUE(up);}/* * arc_start - open the devices and initialize data for processing */static intarc_start( int unit, struct peer *peer ){ register struct arcunit *up; struct refclockproc *pp; int fd; char device[20];#ifdef HAVE_TERMIOS struct termios arg;#endif msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit);#ifdef 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); if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) return(0);#ifdef 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 DEBUG if(debug) { printf("arc: opened RS232 port with file descriptor %d.\n", fd); }#endif#ifdef HAVE_TERMIOS tcgetattr(fd, &arg); 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 msyslog(LOG_ERR, "ARCRON: termios not supported in this driver"); (void)close(fd); return 0;#endif up = (struct arcunit *) emalloc(sizeof(struct arcunit)); if(!up) { (void) close(fd); return(0); } /* Set structure to all zeros... */ 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; if (peer->MODE > 3) { msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); return 0; }#ifdef DEBUG if(debug) { printf("arc: mode = %d.\n", peer->MODE); }#endif switch (peer->MODE) { case 1: memcpy((char *)&pp->refid, REFID_MSF, 4); break; case 2: memcpy((char *)&pp->refid, REFID_DCF77, 4); break; case 3: memcpy((char *)&pp->refid, REFID_WWVB, 4); break; default: memcpy((char *)&pp->refid, REFID, 4); break; } /* Spread out resyncs so that they should remain separated. */ up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009;#if 0 /* Not needed because of zeroing of arcunit structure... */ up->resyncing = 0; /* Not resyncing yet. */ up->saved_flags = 0; /* Default is all flags off. */ /* Clear send buffer out... */ { int i; for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; } }#endif#ifdef ARCRON_KEEN up->quality = QUALITY_UNKNOWN; /* Trust the clock immediately. */#else up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */#endif peer->action = arc_event_handler; ENQUEUE(up); return(1);}/* * arc_shutdown - shut down the clock */static voidarc_shutdown( int unit, struct peer *peer ){ register struct arcunit *up; struct refclockproc *pp; peer->action = dummy_event_handler; pp = peer->procptr; up = (struct arcunit *)pp->unitptr; io_closeclock(&pp->io); free(up);}/*Compute space left in output buffer.*/static intspace_left( register struct arcunit *up ){ int spaceleft;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -