📄 160
字号:
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); } /* 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; memcpy((char *)&pp->refid, REFID, 4); /* 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 /* Set up event structure. */ up->ev.peer = peer; up->ev.event_handler = arc_event_handler; ENQUEUE(up); /* Start ticking. */ return(1);}/* * arc_shutdown - shut down the clock */static voidarc_shutdown(unit, peer) int unit; struct peer *peer;{ register struct arcunit *up; struct refclockproc *pp; pp = peer->procptr; up = (struct arcunit *)pp->unitptr; up->ev.event_handler = dummy_event_handler; TIMER_DEQUEUE(&(up->ev)); /* Stop ticking. */ io_closeclock(&pp->io); free(up);}/*Compute space left in output buffer.*/static int space_left(up)register struct arcunit *up;{ int spaceleft; /* Compute space left in buffer after any pending output. */ for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft) { if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } } return(spaceleft);}/*Send command by copying into command buffer as far forward as possible,after any pending output.Indicate an error by returning 0 if there is not space for the command.*/static intsend_slow(up, fd, s)register struct arcunit *up;int fd;char *s;{ int sl = strlen(s); int spaceleft = space_left(up);#ifdef ARCRON_DEBUG if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); }#endif if(spaceleft < sl) { /* Should not normally happen... */#ifdef ARCRON_DEBUG syslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)", sl, spaceleft);#endif return(0); /* FAILED! */ } /* Copy in the command to be sent. */ while(*s) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; } return(1);}#ifdef ARCRON_OWN_FILTERstatic int arc_refclock_process P((struct refclockproc *, int, int));static int arc_refclock_sample P((l_fp *, struct refclockproc *, int, int));static int arc_refclock_cmpl_fp P((const void *, const void *));#endif/* Macro indicating action we will take for different quality values. */#define quality_action(q) \ (((q) == QUALITY_UNKNOWN) ? "UNKNOWN, will use clock anyway" : \ (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \ "OK, will use clock"))/* * arc_receive - receive data from the serial interface */static voidarc_receive(rbufp) struct recvbuf *rbufp;{ register struct arcunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; char c; int i, n, wday, month, bst, status; int last_offset; /* * Initialize pointers and read the timecode and timestamp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct arcunit *)pp->unitptr; /* If the command buffer is empty, and we are resyncing, insert a g\r quality request into it to poll for signal quality again. */ if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) {#ifdef DEBUG if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); }#endif send_slow(up, pp->io.fd, "g\r"); } /* The `last_offset' is the offset in lastcode[] of the last byte received, and which we assume actually received the input timestamp. (When we get round to using tty_clk and it is available, we assume that we will receive the whole timecode with the trailing \r, and that that \r will be timestamped. But this assumption also works if receive the characters one-by-one.) */ last_offset = pp->lencode+rbufp->recv_length - 1; /* We catch a timestamp iff: * The command code is `o' for a timestamp. * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have exactly char in the buffer (the command code) so that we only sample the first character of the timecode as our `on-time' character. * The first character in the buffer is not the echoed `\r' from the `o` command (so if we are to timestamp an `\r' it must not be first in the receive buffer with lencode==1. (Even if we had other characters following it, we probably would have a premature timestamp on the '\r'.) * We have received at least one character (I cannot imagine how it could be otherwise, but anyway...). */ c = rbufp->recv_buffer[0]; if((pp->lastcode[0] == 'o') &&#ifndef ARCRON_MULTIPLE_SAMPLES (pp->lencode == 1) &&#endif ((pp->lencode != 1) || (c != '\r')) && (last_offset >= 1)) { /* Note that the timestamp should be corrected if >1 char rcvd. */ l_fp timestamp; timestamp = rbufp->recv_time;#ifdef DEBUG if(debug) { /* Show \r as `R', other non-printing char as `?'. */ printf("arc: stamp -->%c<-- (%d chars rcvd)\n", ((c == '\r') ? 'R' : (isgraph(c) ? c : '?')), rbufp->recv_length);#endif } /* Now correct timestamp by offset of last byte received---we subtract from the receive time the delay implied by the extra characters received. Reject the input if the resulting code is too long, but allow for the trailing \r, normally not used but a good handle for tty_clk or somesuch kernel timestamper. */ if(last_offset > LENARC) {#ifdef ARCRON_DEBUG if(debug) { printf("arc: input code too long (%d cf %d); rejected.\n", last_offset, LENARC); }#endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } L_SUBUF(×tamp, charoffsets[last_offset]);#ifdef ARCRON_DEBUG if(debug > 1) { printf("arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", ((rbufp->recv_length > 1) ? "*** " : ""), rbufp->recv_length, last_offset, mfptoms((unsigned long)0, charoffsets[last_offset], 1)); }#endif#ifdef ARCRON_MULTIPLE_SAMPLES /* If taking multiple samples, capture the current adjusted sample iff: * No timestamp has yet been captured (it is zero), OR * This adjusted timestamp is earlier than the one already captured, on the grounds that this one suffered less delay in being delivered to us and is more accurate. */ if(L_ISZERO(&(up->lastrec)) || L_ISGEQ(&(up->lastrec), ×tamp))#endif {#ifdef ARCRON_DEBUG if(debug > 1) { printf("arc: system timestamp captured.\n");#ifdef ARCRON_MULTIPLE_SAMPLES if(!L_ISZERO(&(up->lastrec))) { l_fp diff; diff = up->lastrec; L_SUB(&diff, ×tamp); printf("arc: adjusted timestamp by -%sms.\n", mfptoms(diff.l_i, diff.l_f, 3)); }#endif }#endif up->lastrec = timestamp; } } /* Just in case we still have lots of rubbish in the buffer... */ /* ...and to avoid the same timestamp being reused by mistake, */ /* eg on receipt of the \r coming in on its own after the */ /* timecode. */ if(pp->lencode >= LENARC) {#ifdef ARCRON_DEBUG if(debug && (rbufp->recv_buffer[0] != '\r')) { printf("arc: rubbish in pp->lastcode[].\n"); }#endif pp->lencode = 0; return; } /* Append input to code buffer, avoiding overflow. */ for(i = 0; i < rbufp->recv_length; i++) { if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */ c = rbufp->recv_buffer[i]; /* Drop trailing '\r's and drop `h' command echo totally. */ if(c != '\r' && c != 'h') { pp->lastcode[pp->lencode++] = c; } /* If we've just put an `o' in the lastcode[0], clear the timestamp in anticipation of a timecode arriving soon. We would expect to get to process this before any of the timecode arrives. */ if((c == 'o') && (pp->lencode == 1)) { L_CLR(&(up->lastrec));#ifdef ARCRON_DEBUG if(debug > 1) { printf("arc: clearing timestamp.\n"); }#endif } } /* Handle a quality message. */ if(pp->lastcode[0] == 'g') { int r, q; if(pp->lencode < 3) { return; } /* Need more data... */ r = (pp->lastcode[1] & 0x7f); /* Strip parity. */ q = (pp->lastcode[2] & 0x7f); /* Strip parity. */ if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || ((r & 0x70) != 0x30)) { /* Badly formatted response. */#ifdef ARCRON_DEBUG if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); }#endif return; } if(r == '3') { /* Only use quality value whilst sync in progress. */ up->quality = (q & 0xf);#ifdef DEBUG if(debug) { printf("arc: signal quality %d.\n", up->quality); }#endif } else if( /* (r == '2') && */ up->resyncing) {#ifdef DEBUG if(debug) { printf("arc: sync finished, signal quality %d: %s\n", up->quality, quality_action(up->quality)); }#endif syslog(LOG_NOTICE, "ARCRON: sync finished, signal quality %d: %s", up->quality, quality_action(up->quality)); up->resyncing = 0; /* Resync is over. */#ifdef ARCRON_KEEN /* Clock quality dubious; resync earlier than usual. */ if((up->quality == QUALITY_UNKNOWN) || (up->quality < MIN_CLOCK_QUALITY_OK)) { up->next_resync = current_time + RETRY_RESYNC_TIME; }#endif } pp->lencode = 0; return; } /* Stop now if this is not a timecode message. */ if(pp->lastcode[0] != 'o') { pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } /* If we don't have enough data, wait for more... */ if(pp->lencode < LENARC) { return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -