예제 #1
0
static void
ulink_poll(
	int unit,
	struct peer *peer
	)
{
        struct refclockproc *pp;
        char pollchar;

        pp = peer->procptr;
        pollchar = 'T';
	if (pp->sloppyclockflag & CLK_FLAG1) {
	        if (write(pp->io.fd, &pollchar, 1) != 1)
        	        refclock_report(peer, CEVNT_FAULT);
        	else
      	            pp->polls++;
	}
	else
      	            pp->polls++;

        if (peer->burst > 0)
                return;
        if (pp->coderecv == pp->codeproc) {
                refclock_report(peer, CEVNT_TIMEOUT);
                return;
        }
        pp->lastref = pp->lastrec;
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
        peer->burst = NSTAGE;

}
예제 #2
0
/*
 * as2201_poll - called by the transmit procedure
 *
 * We go to great pains to avoid changing state here, since there may be
 * more than one eavesdropper receiving the same timecode.
 */
static void
as2201_poll(
	int unit,
	struct peer *peer
	)
{
	struct refclockproc *pp;

	/*
	 * Send a "\r*toc\r" to get things going. We go to great pains
	 * to avoid changing state, since there may be more than one
	 * eavesdropper watching the radio.
	 */
	pp = peer->procptr;
	if (write(pp->io.fd, "\r*toc\r", 6) != 6) {
		refclock_report(peer, CEVNT_FAULT);
	} else {
		pp->polls++;
		if (!(pp->sloppyclockflag & CLK_FLAG2))
			get_systime(&pp->lastrec);
	}
        if (pp->coderecv == pp->codeproc) {
                refclock_report(peer, CEVNT_TIMEOUT);
                return;
        }
        refclock_receive(peer);
}
예제 #3
0
/*
 * acts_disc - disconnect the call and clean the place up.
 */
static void
acts_disc (
	struct peer *peer
	)
{
	struct actsunit *up;
	struct refclockproc *pp;
	int	dtr = TIOCM_DTR;

	/*
	 * We get here if the call terminated successfully or if an
	 * error occured. If the median filter has something in it,
	 * feed the data to the clock filter. If a modem port, drop DTR
	 * to force command mode and send modem hangup.
	 */
	pp = peer->procptr;
	up = (struct actsunit *)pp->unitptr;
	if (up->msgcnt > 0)
		refclock_receive(peer);
	if (!(pp->sloppyclockflag & CLK_FLAG3)) {
		ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr);
		write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP));
	}
	up->timer = SETUP;
	up->state = S_CLOSE;
}
예제 #4
0
/*
 * atom_poll - called by the transmit procedure
 */
static void
atom_poll(
	int unit,		/* unit number (not used) */
	struct peer *peer	/* peer structure pointer */
	)
{
	struct refclockproc *pp;

	/*
	 * Don't wiggle the clock until some other driver has numbered
	 * the seconds.
	 */
	if (sys_leap == LEAP_NOTINSYNC)
		return;

	pp = peer->procptr;
	pp->polls++;
	if (pp->codeproc == pp->coderecv) {
		peer->flags &= ~FLAG_PPS;
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
}
예제 #5
0
/*
 * wwvb_poll - called by the transmit procedure
 */
static void
wwvb_poll(
	int unit,
	struct peer *peer
	)
{
	register struct wwvbunit *up;
	struct refclockproc *pp;

	/*
	 * Sweep up the samples received since the last poll. If none
	 * are received, declare a timeout and keep going.
	 */
	pp = peer->procptr;
	up = pp->unitptr;
	pp->polls++;

	/*
	 * If the monitor flag is set (flag4), we dump the internal
	 * quality table at the first timecode beginning the day.
	 */
	if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour <
	    (int)up->lasthour)
		up->linect = MONLIN;
	up->lasthour = (u_char)pp->hour;

	/*
	 * Process median filter samples. If none received, declare a
	 * timeout and keep going.
	 */
#ifdef HAVE_PPSAPI
	if (up->pcount == 0) {
		peer->flags &= ~FLAG_PPS;
		peer->precision = PRECISION;
	}
	if (up->tcount == 0) {
		pp->coderecv = pp->codeproc;
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	up->pcount = up->tcount = 0;
#else /* HAVE_PPSAPI */
	if (pp->coderecv == pp->codeproc) {
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
#endif /* HAVE_PPSAPI */
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
	if (debug)
		printf("wwvb: timecode %d %s\n", pp->lencode,
		    pp->a_lastcode);
#endif
}
예제 #6
0
static void
gpsd_poll(
	int     unit,
	peerT * peer)
{
	clockprocT * const pp = peer->procptr;
	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
	u_int   tc_max;

	++pp->polls;

	/* find the dominant error */
	tc_max = max(up->tc_btime, up->tc_bdate);
	tc_max = max(tc_max, up->tc_breply);

	if (pp->coderecv != pp->codeproc) {
		/* all is well */
		pp->lastref = pp->lastrec;
		refclock_receive(peer);
	} else {
		/* not working properly, admit to it */
		peer->flags    &= ~FLAG_PPS;
		peer->precision = PRECISION;

		if (-1 == pp->io.fd) {
			/* not connected to GPSD: clearly not working! */
			refclock_report(peer, CEVNT_FAULT);
		} else if (tc_max == up->tc_breply) {
			refclock_report(peer, CEVNT_BADREPLY);
		} else if (tc_max == up->tc_btime) {
			refclock_report(peer, CEVNT_BADTIME);
		} else if (tc_max == up->tc_bdate) {
			refclock_report(peer, CEVNT_BADDATE);
		} else {
			refclock_report(peer, CEVNT_TIMEOUT);
		}
	}

	if (pp->sloppyclockflag & CLK_FLAG4)
		gpsd_clockstats(unit, peer);

	/* clear tallies for next round */
	up->tc_good = up->tc_btime = up->tc_bdate =
	    up->tc_breply = up->tc_recv = 0;
}
예제 #7
0
/*
 * atom_poll - called by the transmit procedure
 */
static void
atom_poll(
	int unit,		/* unit number (not used) */
	struct peer *peer	/* peer structure pointer */
	)
{
	struct ppsunit *up;
	struct refclockproc *pp;

	UNUSED_ARG(unit);

	pp = peer->procptr;
	up = (struct ppsunit *)pp->unitptr;

	/*
	 * Don't wiggle the clock until some other driver has numbered
	 * the seconds.
	 */
	if (sys_leap == LEAP_NOTINSYNC) {
		pp->codeproc = pp->coderecv;  // xxx ??
		up->pcount = up->scount = up->kcount = up->rcount = 0;
		return;
        }

	pp->polls++;

	mprintf_clock_stats(&peer->srcadr,
	    "%ld %d %d %d %d",
	    up->atom.sequence,
	    up->pcount, up->scount, up->kcount, up->rcount);
	up->pcount = up->scount = up->kcount = up->rcount = 0;

	if (pp->codeproc == pp->coderecv) {
		peer->flags &= ~FLAG_PPS;
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
}
예제 #8
0
/*
 * shm_poll - called by the transmit procedure
 */
static void
shm_poll(
	int unit,
	struct peer *peer
	)
{
	struct refclockproc * const pp = peer->procptr;
	struct shmunit *      const up = pp->unitptr;
	int major_error;

	pp->polls++;

	/* get dominant reason if we have no samples at all */
	major_error = max(up->notready, up->bad);
	major_error = max(major_error, up->clash);

        /*
         * Process median filter samples. If none received, see what
         * happened, tell the core and keep going.
         */
        if (pp->coderecv != pp->codeproc) {
		/* have some samples, everything OK */
		pp->lastref = pp->lastrec;
		refclock_receive(peer);
	} else if (NULL == up->shm) { /* is this possible at all? */
		/* we're out of business without SHM access */
		refclock_report(peer, CEVNT_FAULT);
	} else if (major_error == up->clash) {
		/* too many collisions is like a bad signal */
                refclock_report(peer, CEVNT_PROP);
	} else if (major_error == up->bad) {
		/* too much stale/bad/garbled data */
                refclock_report(peer, CEVNT_BADREPLY);
	} else {
		/* in any other case assume it's just a timeout */
                refclock_report(peer, CEVNT_TIMEOUT);
        }
	/* shm_clockstats() clears the tallies, so it must be last... */
	shm_clockstats(unit, peer);
}
예제 #9
0
/*
 * arb_poll - called by the transmit procedure
 */
static void
arb_poll(
	int unit,
	struct peer *peer
	)
{
	register struct arbunit *up;
	struct refclockproc *pp;

	/*
	 * Time to poll the clock. The Arbiter clock responds to a "B5"
	 * by returning a timecode in the format specified above.
	 * Transmission occurs once per second, unless turned off by a
	 * "B0". Note there is no checking on state, since this may not
	 * be the only customer reading the clock. Only one customer
	 * need poll the clock; all others just listen in.
	 */
	pp = peer->procptr;
	up = pp->unitptr;
	pp->polls++;
	up->tcswitch = 0;
	if (write(pp->io.fd, "TQ", 2) != 2)
		refclock_report(peer, CEVNT_FAULT);

	/*
	 * Process median filter samples. If none received, declare a
	 * timeout and keep going.
	 */
	if (pp->coderecv == pp->codeproc) {
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
	if (debug)
		printf("arbiter: timecode %d %s\n",
		   pp->lencode, pp->a_lastcode);
#endif
}
예제 #10
0
/*
 * pst_poll - called by the transmit procedure
 */
static void
pst_poll(
	int unit,
	struct peer *peer
	)
{
	register struct pstunit *up;
	struct refclockproc *pp;

	/*
	 * Time to poll the clock. The PSTI/Traconex clock responds to a
	 * "QTQDQMT" by returning a timecode in the format specified
	 * above. Note there is no checking on state, since this may not
	 * be the only customer reading the clock. Only one customer
	 * need poll the clock; all others just listen in. If the clock
	 * becomes unreachable, declare a timeout and keep going.
	 */
	pp = peer->procptr;
	up = (struct pstunit *)pp->unitptr;
	up->tcswitch = 0;
	up->lastptr = pp->a_lastcode;
	if (write(pp->io.fd, "QTQDQMT", 6) != 6)
		refclock_report(peer, CEVNT_FAULT);
	if (peer->burst > 0)
		return;
	if (pp->coderecv == pp->codeproc) {
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
#ifdef DEBUG
	if (debug)
		printf("pst: timecode %d %s\n", pp->lencode,
		    pp->a_lastcode);
#endif
	peer->burst = MAXSTAGE;
	pp->polls++;
}
예제 #11
0
/*
 * leitch_process - process a pile of samples from the clock
 *
 * This routine uses a three-stage median filter to calculate offset and
 * dispersion. reduce jitter. The dispersion is calculated as the span
 * of the filter (max - min), unless the quality character (format 2) is
 * non-blank, in which case the dispersion is calculated on the basis of
 * the inherent tolerance of the internal radio oscillator, which is
 * +-2e-5 according to the radio specifications.
 */
static void
leitch_process(
	struct leitchunit *leitch
	)
{
	l_fp off;
	l_fp tmp_fp;
      /*double doffset;*/

	off = leitch->reftime1;
	L_SUB(&off,&leitch->codetime1);
	tmp_fp = leitch->reftime2;
	L_SUB(&tmp_fp,&leitch->codetime2);
	if (L_ISGEQ(&off,&tmp_fp))
	    off = tmp_fp;
	tmp_fp = leitch->reftime3;
	L_SUB(&tmp_fp,&leitch->codetime3);

	if (L_ISGEQ(&off,&tmp_fp))
	    off = tmp_fp;
      /*LFPTOD(&off, doffset);*/
	refclock_receive(leitch->peer);
}
예제 #12
0
/*
 * arc_receive - receive data from the serial interface
 */
static void
arc_receive(
	struct recvbuf *rbufp
	)
{
	register struct arcunit *up;
	struct refclockproc *pp;
	struct peer *peer;
	char c;
	int i, n, wday, month, flags, status;
	int arc_last_offset;
	static int quality_average = 0;
	static int quality_sum = 0;
	static int quality_polls = 0;

	/*
	 * 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 `arc_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.)
	*/
	arc_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->a_lastcode[0] == 'o') &&
#ifndef ARCRON_MULTIPLE_SAMPLES
	   (pp->lencode == 1) &&
#endif
	   ((pp->lencode != 1) || (c != '\r')) &&
	   (arc_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((int)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(arc_last_offset > LENARC) {
#ifdef DEBUG
			if(debug) {
				printf("arc: input code too long (%d cf %d); rejected.\n",
				       arc_last_offset, LENARC);
			}
#endif
			pp->lencode = 0;
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}

		L_SUBUF(&timestamp, charoffsets[arc_last_offset]);
#ifdef 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,
				arc_last_offset,
				mfptoms((unsigned long)0,
					charoffsets[arc_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), &timestamp))
#endif
		{
#ifdef 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, &timestamp);
					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 DEBUG
		if(debug && (rbufp->recv_buffer[0] != '\r'))
		{ printf("arc: rubbish in pp->a_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->a_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 DEBUG
			if(debug > 1) { printf("arc: clearing timestamp.\n"); }
#endif
		}
	}
	if (pp->lencode == 0) return;

	/* Handle a quality message. */
	if(pp->a_lastcode[0] == 'g') {
		int r, q;

		if(pp->lencode < 3) { return; } /* Need more data... */
		r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */
		q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */
		if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) ||
		   ((r & 0x70) != 0x30)) {
			/* Badly formatted response. */
#ifdef 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. */
			if (up->quality_stamp < current_time) {
				struct calendar cal;
				l_fp new_stamp;
			
				get_systime (&new_stamp);
				caljulian (new_stamp.l_ui, &cal);
				up->quality_stamp = 
					current_time + 60 - cal.second + 5;
				quality_sum = 0;
				quality_polls = 0;
			}
			quality_sum += (q & 0xf);
			quality_polls++;
			quality_average = (quality_sum / quality_polls);
#ifdef DEBUG
			if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); }
#endif
		} else if( /* (r == '2') && */ up->resyncing) {
			up->quality = quality_average;
#ifdef DEBUG
			if(debug)
			{
				printf("arc: sync finished, signal quality %d: %s\n",
				       up->quality,
				       quality_action(up->quality));
			}
#endif
			msyslog(LOG_NOTICE,
				"ARCRON: sync finished, signal quality %d: %s",
				up->quality,
				quality_action(up->quality));
			up->resyncing = 0; /* Resync is over. */
			quality_average = 0;
			quality_sum = 0;
			quality_polls = 0;

#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->a_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; }


	/* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */
#ifdef DEBUG
	if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); }
#endif

	/* But check that we actually captured a system timestamp on it. */
	if(L_ISZERO(&(up->lastrec))) {
#ifdef DEBUG
		if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); }
#endif
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	/*
	  Append a mark of the clock's received signal quality for the
	  benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown'
	  quality value to `6' for his s/w) and terminate the string for
	  sure.  This should not go off the buffer end.
	*/
	pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ?
				       '6' : ('0' + up->quality));
	pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */

#ifdef PRE_NTP420
	/* We don't use the micro-/milli- second part... */
	pp->usec = 0;
	pp->msec = 0;
#else
	/* We don't use the nano-second part... */
	pp->nsec = 0;
#endif	
	/* Validate format and numbers. */
	if (pp->a_lastcode[0] != 'o'
		|| !get2(pp->a_lastcode + 1, &pp->hour)
		|| !get2(pp->a_lastcode + 3, &pp->minute)
		|| !get2(pp->a_lastcode + 5, &pp->second)
		|| !get1(pp->a_lastcode + 7, &wday)
		|| !get2(pp->a_lastcode + 8, &pp->day)
		|| !get2(pp->a_lastcode + 10, &month)
		|| !get2(pp->a_lastcode + 12, &pp->year)) {
#ifdef DEBUG
		/* Would expect to have caught major problems already... */
		if(debug) { printf("arc: badly formatted data.\n"); }
#endif
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	flags = pp->a_lastcode[14];
	status = pp->a_lastcode[15];
#ifdef DEBUG
	if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); }
#endif
	n = 9;

	/*
	  Validate received values at least enough to prevent internal
	  array-bounds problems, etc.
	*/
	if((pp->hour < 0) || (pp->hour > 23) ||
	   (pp->minute < 0) || (pp->minute > 59) ||
	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
	   (wday < 1) || (wday > 7) ||
	   (pp->day < 1) || (pp->day > 31) ||
	   (month < 1) || (month > 12) ||
	   (pp->year < 0) || (pp->year > 99)) {
		/* Data out of range. */
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}


	if(peer->MODE == 0) { /* compatiblity to original version */
		int bst = flags;
		/* Check that BST/UTC bits are the complement of one another. */
		if(!(bst & 2) == !(bst & 4)) {
			pp->lencode = 0;
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
	}
	if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); }

	/* Year-2000 alert! */
	/* Attempt to wrap 2-digit date into sensible window. */
	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* Y2KFixes */
	pp->year += 1900;	/* use full four-digit year */	/* Y2KFixes */
	/*
	  Attempt to do the right thing by screaming that the code will
	  soon break when we get to the end of its useful life.  What a
	  hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
	*/
	if(pp->year >= YEAR_PIVOT+2000-2 ) {  			/* Y2KFixes */
		/*This should get attention B^> */
		msyslog(LOG_NOTICE,
			"ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
	}
#ifdef DEBUG
	if(debug) {
		printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n",
		       n,
		       pp->hour, pp->minute, pp->second,
		       pp->day, month, pp->year, flags, status);
	}
#endif

	/*
	  The status value tested for is not strictly supported by the
	  clock spec since the value of bit 2 (0x4) is claimed to be
	  undefined for MSF, yet does seem to indicate if the last resync
	  was successful or not.
	*/
	pp->leap = LEAP_NOWARNING;
	status &= 0x7;
	if(status == 0x3) {
		if(status != up->status)
		{ msyslog(LOG_NOTICE, "ARCRON: signal acquired"); }
	} else {
		if(status != up->status) {
			msyslog(LOG_NOTICE, "ARCRON: signal lost");
			pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */
			up->status = status;
			pp->lencode = 0;
			refclock_report(peer, CEVNT_FAULT);
			return;
		}
	}
	up->status = status;

	if (peer->MODE == 0) { /* compatiblity to original version */
		int bst = flags;

		pp->day += moff[month - 1];

		if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */

		/* Convert to UTC if required */
		if(bst & 2) {
			pp->hour--;
			if (pp->hour < 0) {
				pp->hour = 23;
				pp->day--;
				/* If we try to wrap round the year
				 * (BST on 1st Jan), reject.*/
				if(pp->day < 0) {
					pp->lencode = 0;
					refclock_report(peer, CEVNT_BADTIME);
					return;
				}
			}
		}
	}

	if(peer->MODE > 0) {
		if(pp->sloppyclockflag & CLK_FLAG1) {
			struct tm  local;
			struct tm *gmtp;
			time_t	   unixtime;

			/*
			 * Convert to GMT for sites that distribute localtime.
			 * This means we have to do Y2K conversion on the
			 * 2-digit year; otherwise, we get the time wrong.
			 */

			memset(&local, 0, sizeof(local));

			local.tm_year  = pp->year-1900;
			local.tm_mon   = month-1;
			local.tm_mday  = pp->day;
			local.tm_hour  = pp->hour;
			local.tm_min   = pp->minute;
			local.tm_sec   = pp->second;
			switch (peer->MODE) {
			    case 1:
				local.tm_isdst = (flags & 2);
				break;
			    case 2:
				local.tm_isdst = (flags & 2);
				break;
			    case 3:
				switch (flags & 3) {
				    case 0: /* It is unclear exactly when the 
					       Arcron changes from DST->ST and 
					       ST->DST. Testing has shown this
					       to be irregular. For the time 
					       being, let the OS decide. */
					local.tm_isdst = 0;
#ifdef DEBUG
					if (debug)
					    printf ("arc: DST = 00 (0)\n"); 
#endif
					break;
				    case 1: /* dst->st time */
					local.tm_isdst = -1;
#ifdef DEBUG
					if (debug) 
					    printf ("arc: DST = 01 (1)\n"); 
#endif
					break;
				    case 2: /* st->dst time */
					local.tm_isdst = -1;
#ifdef DEBUG
					if (debug) 
					    printf ("arc: DST = 10 (2)\n"); 
#endif
					break;
				    case 3: /* dst time */
				        local.tm_isdst = 1;
#ifdef DEBUG
					if (debug) 
					    printf ("arc: DST = 11 (3)\n"); 
#endif
					break;
				}
				break;
			    default:
				msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d",
					peer->MODE);
				return;
				break;
			}
			unixtime = mktime (&local);
			if ((gmtp = gmtime (&unixtime)) == NULL)
			{
				pp->lencode = 0;
				refclock_report (peer, CEVNT_FAULT);
				return;
			}
			pp->year = gmtp->tm_year+1900;
			month = gmtp->tm_mon+1;
			pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
			/* pp->day = gmtp->tm_yday; */
			pp->hour = gmtp->tm_hour;
			pp->minute = gmtp->tm_min;
			pp->second = gmtp->tm_sec;
#ifdef DEBUG
			if (debug)
			{
				printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
					pp->year,month,gmtp->tm_mday,pp->hour,pp->minute,
					pp->second);
			}
#endif
		} else 
		{
			/*
			* For more rational sites distributing UTC
			*/
			pp->day    = ymd2yd(pp->year,month,pp->day);
		}
	}

	if (peer->MODE == 0) { /* compatiblity to original version */
				/* If clock signal quality is 
				 * unknown, revert to default PRECISION...*/
		if(up->quality == QUALITY_UNKNOWN) { 
			peer->precision = PRECISION; 
		} else { /* ...else improve precision if flag3 is set... */
			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
					   HIGHPRECISION : PRECISION);
		}
	} else {
		if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) {
			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
					   HIGHPRECISION : PRECISION);
		} else if (up->quality == QUALITY_UNKNOWN) {
			peer->precision = PRECISION;
		} else {
			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
					   HIGHPRECISION : PRECISION);
		}
	}

	/* Notice and log any change (eg from initial defaults) for flags. */
	if(up->saved_flags != pp->sloppyclockflag) {
#ifdef DEBUG
		msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
			((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
			((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
			((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
			((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
		/* Note effects of flags changing... */
		if(debug) {
			printf("arc: PRECISION = %d.\n", peer->precision);
		}
#endif
		up->saved_flags = pp->sloppyclockflag;
	}

	/* Note time of last believable timestamp. */
	pp->lastrec = up->lastrec;

#ifdef ARCRON_LEAPSECOND_KEEN
	/* Find out if a leap-second might just have happened...
	   (ie is this the first hour of the first day of Jan or Jul?)
	*/
	if((pp->hour == 0) &&
	   (pp->day == 1) &&
	   ((month == 1) || (month == 7))) {
		if(possible_leap >= 0) {
			/* A leap may have happened, and no resync has started yet...*/
			possible_leap = 1;
		}
	} else {
		/* Definitely not leap-second territory... */
		possible_leap = 0;
	}
#endif

	if (!refclock_process(pp)) {
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	refclock_receive(peer);
}
예제 #13
0
/*
 * acts_timeout - called on timeout
 */
static void
acts_timeout(
	struct peer *peer,
	teModemState	dstate
	)
{
	struct actsunit *up;
	struct refclockproc *pp;
	int	fd;
	int	rc;
	char	device[20];
	char	lockfile[128], pidbuf[8];

	/*
	 * The state machine is driven by messages from the modem,
	 * when first started and at timeout.
	 */
	pp = peer->procptr;
	up = pp->unitptr;
	switch (dstate) {

	/*
	 * System poll event. Lock the modem port, open the device
	 * and send the setup command.
	 */
	case S_IDLE:
		if (-1 != pp->io.fd)
			return;		/* port is already open */

		/*
		 * Lock the modem port. If busy, retry later. Note: if
		 * something fails between here and the close, the lock
		 * file may not be removed.
		 */
		if (pp->sloppyclockflag & CLK_FLAG2) {
			snprintf(lockfile, sizeof(lockfile), LOCKFILE,
			    up->unit);
			fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
			    0644);
			if (fd < 0) {
				report_event(PEVNT_CLOCK, peer, "acts: port busy");
				return;
			}
			snprintf(pidbuf, sizeof(pidbuf), "%d\n",
			    (u_int)getpid());
			if (write(fd, pidbuf, strlen(pidbuf)) < 0)
				msyslog(LOG_ERR, "acts: write lock fails %m");
			close(fd);
		}

		/*
		 * Open the device in raw mode and link the I/O.
		 */
		snprintf(device, sizeof(device), DEVICE,
		    up->unit);
		fd = refclock_open(device, SPEED232, LDISC_ACTS |
		    LDISC_RAW | LDISC_REMOTE);
		if (fd < 0) {
			msyslog(LOG_ERR, "acts: open fails %m");
			return;
		}
		pp->io.fd = fd;
		if (!io_addclock(&pp->io)) {
			msyslog(LOG_ERR, "acts: addclock fails");
			close(fd);
			pp->io.fd = -1;
			return;
		}
		up->msgcnt = 0;
		up->bufptr = up->buf;

		/*
		 * If the port is directly connected to the device, skip
		 * the modem business and send 'T' for Spectrabum.
		 */
		if (sys_phone[up->retry] == NULL) {
			if (write(pp->io.fd, "T", 1) < 0)
				msyslog(LOG_ERR, "acts: write T fails %m");
			up->state = S_MSG;
			up->timer = TIMECODE;
			return;
		}

		/*
		 * Initialize the modem. This works with Hayes-
		 * compatible modems.
		 */
		mprintf_event(PEVNT_CLOCK, peer, "SETUP %s",
			      modem_setup);
		rc = write(pp->io.fd, modem_setup, strlen(modem_setup));
		if (rc < 0)
			msyslog(LOG_ERR, "acts: write SETUP fails %m");
		write(pp->io.fd, "\r", 1);
		up->state = S_SETUP;
		up->timer = SETUP;
		return;

	/*
	 * In SETUP state the modem did not respond OK to setup string.
	 */
	case S_SETUP:
		report_event(PEVNT_CLOCK, peer, "no modem");
		break;

	/*
	 * In CONNECT state the call did not complete. Abort the call.
	 */
	case S_CONNECT:
		report_event(PEVNT_CLOCK, peer, "no answer");
		break;

	/*
	 * In MSG states no further timecodes are expected. If any
	 * timecodes have arrived, update the clock. In any case,
	 * terminate the call.
	 */
	case S_MSG:
		if (up->msgcnt == 0) {
			report_event(PEVNT_CLOCK, peer, "no timecodes");
		} else {
			pp->lastref = pp->lastrec;
			record_clock_stats(&peer->srcadr, pp->a_lastcode);
			refclock_receive(peer);
		}
		break;
	}
	acts_close(peer);
}
예제 #14
0
/******************************************************************************
 *
 * Function:    tsync_poll()
 * Description: Retrieve time from the TSYNC device.
 *
 * Parameters:
 *     IN:  unit - not used.
 *         *peer - pointer to this reference clock's peer structure
 *     Returns: none.
 *
*******************************************************************************/
static void tsync_poll(int unit, struct peer *peer)
{
    char                 device[32];
    struct refclockproc *pp;
    struct calendar      jt;
    TsyncUnit           *up;
    unsigned char        synch;
    double               seconds;
    int                  err;
    int                  err1;
    int                  err2;
    int                  err3;
    int                  i;
    int                  j;
    unsigned int         itAllocationLength;
    unsigned int         itAllocationLength1;
    unsigned int         itAllocationLength2;
    NtpTimeObj           TimeContext;
    BoardObj             hBoard;
    char                 timeRef[TSYNC_REF_LEN + 1];
    char                 ppsRef [TSYNC_REF_LEN + 1];
    TIME_SCALE           tmscl = TIME_SCALE_UTC;
    LeapSecondObj        leapSec;
    ioctl_trans_di      *it;
    ioctl_trans_di      *it1;
    ioctl_trans_di      *it2;
    l_fp                 offset;
    l_fp                 ltemp;
    ReferenceObj *	 pRefObj;


    /* Construct the device name */
    sprintf(device, "%s%d", DEVICE, (int)peer->refclkunit);

    printf("Polling device number %d...\n", (int)peer->refclkunit);

    /* Open the TSYNC device */
    hBoard.file_descriptor = open(device, O_RDONLY | O_NDELAY, 0777);

    /* If error opening TSYNC device... */
    if (hBoard.file_descriptor < 0)
    {
        msyslog(LOG_ERR, "Couldn't open device");
        return;
    }

    /* If error while initializing the board... */
    if (ioctl(hBoard.file_descriptor, IOCTL_TPRO_OPEN, &hBoard) < 0)
    {
        msyslog(LOG_ERR, "Couldn't initialize device");
        close(hBoard.file_descriptor);
        return;
    }

    /* Allocate memory for ioctl message */
    itAllocationLength =
        (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
        TSYNC_REF_IN_LEN + TSYNC_REF_MAX_OUT_LEN;

    it = (ioctl_trans_di*)alloca(itAllocationLength);
    if (it == NULL) {
        msyslog(LOG_ERR, "Couldn't allocate transaction memory - Reference");
        return;
    }

    /* Build SS_GetRef ioctl message */
    it->dest             = TSYNC_REF_DEST_ID;
    it->iid              = TSYNC_REF_IID;
    it->inPayloadOffset  = TSYNC_REF_IN_PYLD_OFF;
    it->inLength         = TSYNC_REF_IN_LEN;
    it->outPayloadOffset = TSYNC_REF_OUT_PYLD_OFF;
    it->maxOutLength     = TSYNC_REF_MAX_OUT_LEN;
    it->actualOutLength  = 0;
    it->status           = 0;
    memset(it->payloads, 0, TSYNC_REF_MAX_OUT_LEN);

    /* Read the reference from the TSYNC-PCI device */
    err = ioctl(hBoard.file_descriptor,
                 IOCTL_TSYNC_GET,
                (char *)it);

    /* Allocate memory for ioctl message */
    itAllocationLength1 =
        (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
        TSYNC_TMSCL_IN_LEN + TSYNC_TMSCL_MAX_OUT_LEN;

    it1 = (ioctl_trans_di*)alloca(itAllocationLength1);
    if (it1 == NULL) {
        msyslog(LOG_ERR, "Couldn't allocate transaction memory - Time Scale");
        return;
    }

    /* Build CS_GetTimeScale ioctl message */
    it1->dest             = TSYNC_TMSCL_DEST_ID;
    it1->iid              = TSYNC_TMSCL_IID;
    it1->inPayloadOffset  = TSYNC_TMSCL_IN_PYLD_OFF;
    it1->inLength         = TSYNC_TMSCL_IN_LEN;
    it1->outPayloadOffset = TSYNC_TMSCL_OUT_PYLD_OFF;
    it1->maxOutLength     = TSYNC_TMSCL_MAX_OUT_LEN;
    it1->actualOutLength  = 0;
    it1->status           = 0;
    memset(it1->payloads, 0, TSYNC_TMSCL_MAX_OUT_LEN);

    /* Read the Time Scale info from the TSYNC-PCI device */
    err1 = ioctl(hBoard.file_descriptor,
                 IOCTL_TSYNC_GET,
                 (char *)it1);

    /* Allocate memory for ioctl message */
    itAllocationLength2 =
        (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
        TSYNC_LEAP_IN_LEN + TSYNC_LEAP_MAX_OUT_LEN;

    it2 = (ioctl_trans_di*)alloca(itAllocationLength2);
    if (it2 == NULL) {
        msyslog(LOG_ERR, "Couldn't allocate transaction memory - Leap Second");
        return;
    }

    /* Build CS_GetLeapSec ioctl message */
    it2->dest             = TSYNC_LEAP_DEST_ID;
    it2->iid              = TSYNC_LEAP_IID;
    it2->inPayloadOffset  = TSYNC_LEAP_IN_PYLD_OFF;
    it2->inLength         = TSYNC_LEAP_IN_LEN;
    it2->outPayloadOffset = TSYNC_LEAP_OUT_PYLD_OFF;
    it2->maxOutLength     = TSYNC_LEAP_MAX_OUT_LEN;
    it2->actualOutLength  = 0;
    it2->status           = 0;
    memset(it2->payloads, 0, TSYNC_LEAP_MAX_OUT_LEN);

    /* Read the leap seconds info from the TSYNC-PCI device */
    err2 = ioctl(hBoard.file_descriptor,
                 IOCTL_TSYNC_GET,
                 (char *)it2);

    pp = peer->procptr;
    up = (TsyncUnit*)pp->unitptr;

    /* Read the time from the TSYNC-PCI device */
    err3 = ioctl(hBoard.file_descriptor,
                 IOCTL_TPRO_GET_NTP_TIME,
                 (char *)&TimeContext);

    /* Close the TSYNC device */
    close(hBoard.file_descriptor);

    // Check for errors
    if ((err < 0) ||(err1 < 0) || (err2 < 0) || (err3 < 0) ||
        (it->status != 0) || (it1->status != 0) || (it2->status != 0) ||
        (it->actualOutLength  != TSYNC_REF_OUT_LEN) ||
        (it1->actualOutLength != TSYNC_TMSCL_OUT_LEN) ||
        (it2->actualOutLength != TSYNC_LEAP_OUT_LEN)) {
        refclock_report(peer, CEVNT_FAULT);
        return;
    }

    // Extract reference identifiers from ioctl payload
    memset(timeRef, '\0', sizeof(timeRef));
    memset(ppsRef, '\0', sizeof(ppsRef));
    pRefObj = (void *)it->payloads;
    memcpy(timeRef, pRefObj->time, TSYNC_REF_LEN);
    memcpy(ppsRef, pRefObj->pps, TSYNC_REF_LEN);

    // Extract the Clock Service Time Scale and convert to correct byte order
    memcpy(&tmscl, ((TIME_SCALE*)(it1->payloads)), sizeof(tmscl));
    tmscl = ntohl(tmscl);

    // Extract leap second info from ioctl payload and perform byte swapping
    for (i = 0; i < (sizeof(leapSec) / 4); i++)
    {
        for (j = 0; j < 4; j++)
        {
            ((unsigned char*)&leapSec)[(i * 4) + j] =
                    ((unsigned char*)(it2->payloads))[(i * 4) + (3 - j)];
        }
    }

    // Determine time reference ID from reference name
    for (i = 0; RefIdLookupTbl[i].pRef != NULL; i++)
    {
       // Search RefID table
       if (strstr(timeRef, RefIdLookupTbl[i].pRef) != NULL)
       {
          // Found the matching string
          break;
       }
    }

    // Determine pps reference ID from reference name
    for (j = 0; RefIdLookupTbl[j].pRef != NULL; j++)
    {
       // Search RefID table
       if (strstr(ppsRef, RefIdLookupTbl[j].pRef) != NULL)
       {
          // Found the matching string
          break;
       }
    }

    // Determine synchronization state from flags
    synch = (TimeContext.timeObj.flags == 0x4) ? 1 : 0;

    // Pull seconds information from time object
    seconds = (double) (TimeContext.timeObj.secsDouble);
    seconds /= (double) 1000000.0;

    /*
    ** Convert the number of microseconds to double and then place in the
    ** peer's last received long floating point format.
    */
    DTOLFP(((double)TimeContext.tv.tv_usec / 1000000.0), &pp->lastrec);

    /*
    ** The specTimeStamp is the number of seconds since 1/1/1970, while the
    ** peer's lastrec time should be compatible with NTP which is seconds since
    ** 1/1/1900.  So Add the number of seconds between 1900 and 1970 to the
    ** specTimeStamp and place in the peer's lastrec long floating point struct.
    */
    pp->lastrec.Ul_i.Xl_ui += (unsigned int)TimeContext.tv.tv_sec +
                                            SECONDS_1900_TO_1970;

    pp->polls++;

    /*
    **  set the reference clock object
    */
    sprintf(pp->a_lastcode, "%03d %02d:%02d:%02.6f",
            TimeContext.timeObj.days, TimeContext.timeObj.hours,
            TimeContext.timeObj.minutes, seconds);

    pp->lencode = strlen (pp->a_lastcode);
    pp->day     = TimeContext.timeObj.days;
    pp->hour    = TimeContext.timeObj.hours;
    pp->minute  = TimeContext.timeObj.minutes;
    pp->second  = (int) seconds;
    seconds     = (seconds - (double) (pp->second / 1.0)) * 1000000000;
    pp->nsec    = (long) seconds;

    /*
    **  calculate year start
    */
    jt.year       = TimeContext.timeObj.year;
    jt.yearday    = 1;
    jt.monthday   = 1;
    jt.month      = 1;
    jt.hour       = 0;
    jt.minute     = 0;
    jt.second     = 0;
    pp->yearstart = caltontp(&jt);

    // Calculate and report reference clock offset
    offset.l_ui = (long)(((pp->day - 1) * 24) + pp->hour + GMT);
    offset.l_ui = (offset.l_ui * 60) + (long)pp->minute;
    offset.l_ui = (offset.l_ui * 60) + (long)pp->second;
    offset.l_ui = offset.l_ui + (long)pp->yearstart;
    offset.l_uf = 0;
    DTOLFP(pp->nsec / 1e9, &ltemp);
    L_ADD(&offset, &ltemp);
    refclock_process_offset(pp, offset, pp->lastrec,
                            pp->fudgetime1);

    // KTS in sync
    if (synch) {
        // Subtract leap second info by one second to determine effective day
        ApplyTimeOffset(&(leapSec.utcDate), -1);

        // If there is a leap second today and the KTS is using a time scale
        // which handles leap seconds then
        if ((tmscl != TIME_SCALE_GPS) && (tmscl != TIME_SCALE_TAI) &&
            (leapSec.utcDate.year == (unsigned int)TimeContext.timeObj.year) &&
            (leapSec.utcDate.doy  == (unsigned int)TimeContext.timeObj.days))
        {
            // If adding a second
            if (leapSec.offset == 1)
            {
                pp->leap = LEAP_ADDSECOND;
            }
            // Else if removing a second
            else if (leapSec.offset == -1)
            {
                pp->leap = LEAP_DELSECOND;
            }
            // Else report no leap second pending (no handling of offsets
            // other than +1 or -1)
            else
            {
                pp->leap = LEAP_NOWARNING;
            }
        }
        // Else report no leap second pending
        else
        {
            pp->leap = LEAP_NOWARNING;
        }

        peer->leap = pp->leap;
        refclock_report(peer, CEVNT_NOMINAL);

        // If reference name reported, then not in holdover
        if ((RefIdLookupTbl[i].pRef != NULL) &&
            (RefIdLookupTbl[j].pRef != NULL))
        {
            // Determine if KTS being synchronized by host (identified as
            // "LOCL")
            if ((strcmp(RefIdLookupTbl[i].pRefId, TSYNC_REF_LOCAL) == 0) ||
                (strcmp(RefIdLookupTbl[j].pRefId, TSYNC_REF_LOCAL) == 0))
            {
                // Clear prefer flag
                peer->flags &= ~FLAG_PREFER;

                // Set reference clock stratum level as unusable
                pp->stratum   = STRATUM_UNSPEC;
                peer->stratum = pp->stratum;

                // If a valid peer is available
                if ((sys_peer != NULL) && (sys_peer != peer))
                {
                    // Store reference peer stratum level and ID
                    up->refStratum = sys_peer->stratum;
                    up->refId      = addr2refid(&sys_peer->srcadr);
                }
            }
            else
            {
                // Restore prefer flag
                peer->flags |= up->refPrefer;

                // Store reference stratum as local clock
                up->refStratum = TSYNC_LCL_STRATUM;
                strncpy((char *)&up->refId, RefIdLookupTbl[j].pRefId,
                    TSYNC_REF_LEN);

                // Set reference clock stratum level as local clock
                pp->stratum   = TSYNC_LCL_STRATUM;
                peer->stratum = pp->stratum;
            }

            // Update reference name
            strncpy((char *)&pp->refid, RefIdLookupTbl[j].pRefId,
                TSYNC_REF_LEN);
            peer->refid = pp->refid;
        }
        // Else in holdover
        else
        {
            // Restore prefer flag
            peer->flags |= up->refPrefer;

            // Update reference ID to saved ID
            pp->refid   = up->refId;
            peer->refid = pp->refid;

            // Update stratum level to saved stratum level
            pp->stratum   = up->refStratum;
            peer->stratum = pp->stratum;
        }
    }
    // Else KTS not in sync
    else {
        // Place local identifier in peer RefID
        strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
        peer->refid = pp->refid;

        // Report not in sync
        pp->leap   = LEAP_NOTINSYNC;
        peer->leap = pp->leap;
    }

    if (pp->coderecv == pp->codeproc) {
        refclock_report(peer, CEVNT_TIMEOUT);
        return;
    }

    record_clock_stats(&peer->srcadr, pp->a_lastcode);
    refclock_receive(peer);

    /* Increment the number of times the reference has been polled */
    pp->polls++;

} /* End - tsync_poll() */
예제 #15
0
/*
 * tt560_poll - called by the transmit procedure
 */
static void
tt560_poll(
	int unit,
	struct peer *peer
	)
{
	register struct tt560unit *up;
	struct refclockproc       *pp;
	time_freeze_reg_t         *tp;
	tt_mem_space_t            *mp;

	int i;
	unsigned int *p_time_t, *tt_mem_t;

	/*
	 * This is the main routine. It snatches the time from the TT560
	 * board and tacks on a local timestamp.
	 */
	pp = peer->procptr;
	up = (struct tt560unit *)pp->unitptr;
	mp = up->tt_mem;
	tp = &up->tt560rawt;

	p_time_t = (unsigned int *)tp;
	tt_mem_t = (unsigned int *)&mp->time_freeze_reg;

	*tt_mem_t = 0;		/* update the time freeze register */
				/* and copy time stamp to memory */
	for (i=0; i < TIME_FREEZE_REG_LEN; i++) {
	    *p_time_t = byte_swap(*tt_mem_t);
	     p_time_t++;
	     tt_mem_t++;
	}

	get_systime(&pp->lastrec);
	pp->polls++;

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. If the timecode has invalid length or is not in
	 * proper format, we declare bad format and exit. Note: we
	 * can't use the sec/usec conversion produced by the driver,
	 * since the year may be suspect. All format error checking is
	 * done by the sprintf() and sscanf() routines.
	 */
	sprintf(pp->a_lastcode,
	    "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
	    tp->hun_day,  tp->tens_day,  tp->unit_day,
	                  tp->tens_hour, tp->unit_hour,
	                  tp->tens_min,  tp->unit_min,
	                  tp->tens_sec,  tp->unit_sec,
	    tp->hun_ms,   tp->tens_ms,   tp->unit_ms,
	    tp->hun_us,   tp->tens_us,   tp->unit_us,
	    tp->status);
	    pp->lencode = strlen(pp->a_lastcode);
#ifdef DEBUG
	if (debug)
		printf("tt560: time %s timecode %d %s\n",
		   ulfptoa(&pp->lastrec, 6), pp->lencode,
		   pp->a_lastcode);
#endif
	if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", 
                  &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->usec)
	    != 5) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	if ((tp->status & 0x6) != 0x6)
		pp->leap = LEAP_NOTINSYNC;
	else
		pp->leap = LEAP_NOWARNING;
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	if (peer->burst > 0)
		return;
	if (pp->coderecv == pp->codeproc) {
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	refclock_receive(peer);
	peer->burst = NSTAGE;
}
예제 #16
0
/*
 * hpgps_receive - receive data from the serial interface
 */
static void
hpgps_receive(
	struct recvbuf *rbufp
	)
{
	register struct hpgpsunit *up;
	struct refclockproc *pp;
	struct peer *peer;
	l_fp trtmp;
	char tcodechar1;        /* identifies timecode format */
	char tcodechar2;        /* identifies timecode format */
	char timequal;          /* time figure of merit: 0-9 */
	char freqqual;          /* frequency figure of merit: 0-3 */
	char leapchar;          /* leapsecond: + or 0 or - */
	char servchar;          /* request for service: 0 = no, 1 = yes */
	char syncchar;          /* time info is invalid: 0 = no, 1 = yes */
	short expectedsm;       /* expected timecode byte checksum */
	short tcodechksm;       /* computed timecode byte checksum */
	int i,m,n;
	int month, day, lastday;
	char *tcp;              /* timecode pointer (skips over the prompt) */
	char prompt[BMAX];      /* prompt in response from receiver */

	/*
	 * Initialize pointers and read the receiver response
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = (struct hpgpsunit *)pp->unitptr;
	*pp->a_lastcode = '\0';
	pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);

#ifdef DEBUG
	if (debug)
	    printf("hpgps: lencode: %d timecode:%s\n",
		   pp->lencode, pp->a_lastcode);
#endif

	/*
	 * If there's no characters in the reply, we can quit now
	 */
	if (pp->lencode == 0)
	    return;

	/*
	 * If linecnt is greater than zero, we are getting information only,
	 * such as the receiver identification string or the receiver status
	 * screen, so put the receiver response at the end of the status
	 * screen buffer. When we have the last line, write the buffer to
	 * the clockstats file and return without further processing.
	 *
	 * If linecnt is zero, we are expecting either the timezone
	 * or a timecode. At this point, also write the response
	 * to the clockstats file, and go on to process the prompt (if any),
	 * timezone, or timecode and timestamp.
	 */


	if (up->linecnt-- > 0) {
		if ((int)(pp->lencode + 2) <= (SMAX - (up->lastptr - up->statscrn))) {
			*up->lastptr++ = '\n';
			(void)strcpy(up->lastptr, pp->a_lastcode);
			up->lastptr += pp->lencode;
		}
		if (up->linecnt == 0) 
		    record_clock_stats(&peer->srcadr, up->statscrn);
               
		return;
	}

	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	pp->lastrec = trtmp;
            
	up->lastptr = up->statscrn;
	*up->lastptr = '\0';
	up->pollcnt = 2;

	/*
	 * We get down to business: get a prompt if one is there, issue
	 * a clear status command if it contains an error indication.
	 * Next, check for either the timezone reply or the timecode reply
	 * and decode it.  If we don't recognize the reply, or don't get the
	 * proper number of decoded fields, or get an out of range timezone,
	 * or if the timecode checksum is bad, then we declare bad format
	 * and exit.
	 *
	 * Timezone format (including nominal prompt):
	 * scpi > -H,-M<cr><lf>
	 *
	 * Timecode format (including nominal prompt):
	 * scpi > T2yyyymmddhhmmssMFLRVcc<cr><lf>
	 *
	 */

	(void)strcpy(prompt,pp->a_lastcode);
	tcp = strrchr(pp->a_lastcode,'>');
	if (tcp == NULL)
	    tcp = pp->a_lastcode; 
	else
	    tcp++;
	prompt[tcp - pp->a_lastcode] = '\0';
	while ((*tcp == ' ') || (*tcp == '\t')) tcp++;

	/*
	 * deal with an error indication in the prompt here
	 */
	if (strrchr(prompt,'E') > strrchr(prompt,'s')){
#ifdef DEBUG
		if (debug)
		    printf("hpgps: error indicated in prompt: %s\n", prompt);
#endif
		if (write(pp->io.fd, "*CLS\r\r", 6) != 6)
		    refclock_report(peer, CEVNT_FAULT);
	}

	/*
	 * make sure we got a timezone or timecode format and 
	 * then process accordingly
	 */
	m = sscanf(tcp,"%c%c", &tcodechar1, &tcodechar2);

	if (m != 2){
#ifdef DEBUG
		if (debug)
		    printf("hpgps: no format indicator\n");
#endif
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	switch (tcodechar1) {

	    case '+':
	    case '-':
		m = sscanf(tcp,"%d,%d", &up->tzhour, &up->tzminute);
		if (m != MTZONE) {
#ifdef DEBUG
			if (debug)
			    printf("hpgps: only %d fields recognized in timezone\n", m);
#endif
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
		if ((up->tzhour < -12) || (up->tzhour > 13) || 
		    (up->tzminute < -59) || (up->tzminute > 59)){
#ifdef DEBUG
			if (debug)
			    printf("hpgps: timezone %d, %d out of range\n",
				   up->tzhour, up->tzminute);
#endif
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
		return;

	    case 'T':
		break;

	    default:
#ifdef DEBUG
		if (debug)
		    printf("hpgps: unrecognized reply format %c%c\n",
			   tcodechar1, tcodechar2);
#endif
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	} /* end of tcodechar1 switch */


	switch (tcodechar2) {

	    case '2':
		m = sscanf(tcp,"%*c%*c%4d%2d%2d%2d%2d%2d%c%c%c%c%c%2hx",
			   &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second,
			   &timequal, &freqqual, &leapchar, &servchar, &syncchar,
			   &expectedsm);
		n = NTCODET2;

		if (m != MTCODET2){
#ifdef DEBUG
			if (debug)
			    printf("hpgps: only %d fields recognized in timecode\n", m);
#endif
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
		break;

	    default:
#ifdef DEBUG
		if (debug)
		    printf("hpgps: unrecognized timecode format %c%c\n",
			   tcodechar1, tcodechar2);
#endif
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	} /* end of tcodechar2 format switch */
           
	/* 
	 * Compute and verify the checksum.
	 * Characters are summed starting at tcodechar1, ending at just
	 * before the expected checksum.  Bail out if incorrect.
	 */
	tcodechksm = 0;
	while (n-- > 0) tcodechksm += *tcp++;
	tcodechksm &= 0x00ff;

	if (tcodechksm != expectedsm) {
#ifdef DEBUG
		if (debug)
		    printf("hpgps: checksum %2hX doesn't match %2hX expected\n",
			   tcodechksm, expectedsm);
#endif
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	/* 
	 * Compute the day of year from the yyyymmdd format.
	 */
	if (month < 1 || month > 12 || day < 1) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}

	if ( ! isleap_4(pp->year) ) {				/* Y2KFixes */
		/* not a leap year */
		if (day > day1tab[month - 1]) {
			refclock_report(peer, CEVNT_BADTIME);
			return;
		}
		for (i = 0; i < month - 1; i++) day += day1tab[i];
		lastday = 365;
	} else {
		/* a leap year */
		if (day > day2tab[month - 1]) {
			refclock_report(peer, CEVNT_BADTIME);
			return;
		}
		for (i = 0; i < month - 1; i++) day += day2tab[i];
		lastday = 366;
	}

	/*
	 * Deal with the timezone offset here. The receiver timecode is in
	 * local time = UTC + :PTIME:TZONE, so SUBTRACT the timezone values.
	 * For example, Pacific Standard Time is -8 hours , 0 minutes.
	 * Deal with the underflows and overflows.
	 */
	pp->minute -= up->tzminute;
	pp->hour -= up->tzhour;

	if (pp->minute < 0) {
		pp->minute += 60;
		pp->hour--;
	}
	if (pp->minute > 59) {
		pp->minute -= 60;
		pp->hour++;
	}
	if (pp->hour < 0)  {
		pp->hour += 24;
		day--;
		if (day < 1) {
			pp->year--;
			if ( isleap_4(pp->year) )		/* Y2KFixes */
			    day = 366;
			else
			    day = 365;
		}
	}

	if (pp->hour > 23) {
		pp->hour -= 24;
		day++;
		if (day > lastday) {
			pp->year++;
			day = 1;
		}
	}

	pp->day = day;

	/*
	 * Decode the MFLRV indicators.
	 * NEED TO FIGURE OUT how to deal with the request for service,
	 * time quality, and frequency quality indicators some day. 
	 */
	if (syncchar != '0') {
		pp->leap = LEAP_NOTINSYNC;
	}
	else {
		pp->leap = LEAP_NOWARNING;
		switch (leapchar) {

		    case '0':
			break;
                     
		    /* See http://bugs.ntp.org/1090
		     * Ignore leap announcements unless June or December.
		     * Better would be to use :GPSTime? to find the month,
		     * but that seems too likely to introduce other bugs.
		     */
		    case '+':
			if ((month==6) || (month==12))
			    pp->leap = LEAP_ADDSECOND;
			break;
                     
		    case '-':
			if ((month==6) || (month==12))
			    pp->leap = LEAP_DELSECOND;
			break;
                     
		    default:
#ifdef DEBUG
			if (debug)
			    printf("hpgps: unrecognized leap indicator: %c\n",
				   leapchar);
#endif
			refclock_report(peer, CEVNT_BADTIME);
			return;
		} /* end of leapchar switch */
	}

	/*
	 * Process the new sample in the median filter and determine the
	 * reference clock offset and dispersion. We use lastrec as both
	 * the reference time and receive time in order to avoid being
	 * cute, like setting the reference time later than the receive
	 * time, which may cause a paranoid protocol module to chuck out
	 * the data.
	 */
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);

	/*
	 * If CLK_FLAG4 is set, ask for the status screen response.
	 */
	if (pp->sloppyclockflag & CLK_FLAG4){
		up->linecnt = 22; 
		if (write(pp->io.fd, ":SYSTEM:PRINT?\r", 15) != 15)
		    refclock_report(peer, CEVNT_FAULT);
	}
}
예제 #17
0
/*
 * dumbclock_receive - receive data from the serial interface
 */
static void
dumbclock_receive(
	struct recvbuf *rbufp
	)
{
	struct dumbclock_unit *up;
	struct refclockproc *pp;
	struct peer *peer;

	l_fp	trtmp;		/* arrival timestamp */
	int	hours;		/* hour-of-day */
	int	minutes;	/* minutes-past-the-hour */
	int	seconds;	/* seconds */
	int	temp;		/* int temp */
	int	got_good;	/* got a good time flag */

	/*
	 * Initialize pointers and read the timecode and timestamp
	 */
	peer = rbufp->recv_peer;
	pp = peer->procptr;
	up = pp->unitptr;
	temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);

	if (temp == 0) {
		if (up->tcswitch == 0) {
			up->tcswitch = 1;
			up->laststamp = trtmp;
		} else
			up->tcswitch = 0;
		return;
	}
	pp->lencode = (u_short)temp;
	pp->lastrec = up->laststamp;
	up->laststamp = trtmp;
	up->tcswitch = 1;

#ifdef DEBUG
	if (debug)
		printf("dumbclock: timecode %d %s\n",
		       pp->lencode, pp->a_lastcode);
#endif

	/*
	 * We get down to business. Check the timecode format...
	 */
	got_good=0;
	if (sscanf(pp->a_lastcode,"%02d:%02d:%02d",
		   &hours,&minutes,&seconds) == 3)
	{
	    struct tm *gmtp;
	    struct tm *lt_p;
	    time_t     asserted_time;	     /* the SPM time based on the composite time+date */
	    struct tm  asserted_tm;	     /* the struct tm of the same */
	    int        adjyear;
	    int        adjmon;
	    time_t     reality_delta;
	    time_t     now;


	    /*
	     * Convert to GMT for sites that distribute localtime.  This
	     * means we have to figure out what day it is.  Easier said
	     * than done...
	     */

	    memset(&asserted_tm, 0, sizeof(asserted_tm));

	    asserted_tm.tm_year  = up->ymd.tm_year;
	    asserted_tm.tm_mon   = up->ymd.tm_mon;
	    asserted_tm.tm_mday  = up->ymd.tm_mday;
	    asserted_tm.tm_hour  = hours;
	    asserted_tm.tm_min   = minutes;
	    asserted_tm.tm_sec   = seconds;
	    asserted_tm.tm_isdst = -1;

#ifdef GET_LOCALTIME
	    asserted_time = mktime (&asserted_tm);
	    time(&now);
#else
#include "GMT unsupported for dumbclock!"
#endif
	    reality_delta = asserted_time - now;

	    /*
	     * We assume that if the time is grossly wrong, it's because we got the
	     * year/month/day wrong.
	     */
	    if (reality_delta > INSANE_SECONDS)
	    {
		asserted_time -= SECSPERDAY; /* local clock behind real time */
	    }
	    else if (-reality_delta > INSANE_SECONDS)
	    {
		asserted_time += SECSPERDAY; /* local clock ahead of real time */
	    }
	    lt_p = localtime(&asserted_time);
	    if (lt_p)
	    {
		up->ymd = *lt_p;
	    }
	    else
	    {
		refclock_report (peer, CEVNT_FAULT);
		return;
	    }

	    if ((gmtp = gmtime (&asserted_time)) == NULL)
	    {
		refclock_report (peer, CEVNT_FAULT);
		return;
	    }
	    adjyear = gmtp->tm_year+1900;
	    adjmon  = gmtp->tm_mon+1;
	    pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
	    pp->hour   = gmtp->tm_hour;
	    pp->minute = gmtp->tm_min;
	    pp->second = gmtp->tm_sec;
#ifdef DEBUG
	    if (debug)
		printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
			adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
			pp->second);
#endif

	    got_good=1;
	}

	if (!got_good)
	{
	    if (up->linect > 0)
	    	up->linect--;
	    else
	    	refclock_report(peer, CEVNT_BADREPLY);
	    return;
	}

	/*
	 * Process the new sample in the median filter and determine the
	 * timecode timestamp.
	 */
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	up->lasthour = (u_char)pp->hour;
}
예제 #18
0
/*
 * local_poll - called by the transmit procedure
 *
 * LOCKCLOCK: If the kernel supports the nanokernel or microkernel
 * system calls, the leap bits are extracted from the kernel. If there
 * is a kernel error or the kernel leap bits are set to 11, the NTP leap
 * bits are set to 11 and the stratum is set to infinity. Otherwise, the
 * NTP leap bits are set to the kernel leap bits and the stratum is set
 * as fudged. This behavior does not faithfully follow the
 * specification, but is probably more appropriate in a multiple-server
 * national laboratory network.
 */
static void
local_poll(
	int unit,
	struct peer *peer
	)
{
#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
	struct timex ntv;
#endif /* KERNEL_PLL LOCKCLOCK */
	struct refclockproc *pp;

	/*
	 * Do no evil unless the house is dark or lit with our own lamp.
	 */
	if (!(sys_peer == NULL || sys_peer == peer))
		return;

#if defined(VMS) && defined(VMS_LOCALUNIT)
	if (unit == VMS_LOCALUNIT) {
		extern void vms_local_poll(struct peer *);

		vms_local_poll(peer);
		return;
	}
#endif /* VMS && VMS_LOCALUNIT */

	pp = peer->procptr;
	pp->polls++;

	/*
	 * Ramble through the usual filtering and grooming code, which
	 * is essentially a no-op and included mostly for pretty
	 * billboards.
	 */
	poll_time = current_time;
	refclock_process_offset(pp, pp->lastrec, pp->lastrec, 0);

	/*
	 * If another process is disciplining the system clock, we set
	 * the leap bits and quality indicators from the kernel.
	 */
#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
	memset(&ntv,  0, sizeof ntv);
	switch (ntp_adjtime(&ntv)) {
	case TIME_OK:
		pp->leap = LEAP_NOWARNING;
		peer->stratum = pp->stratum;
		break;

	case TIME_INS:
		pp->leap = LEAP_ADDSECOND;
		peer->stratum = pp->stratum;
		break;

	case TIME_DEL:
		pp->leap = LEAP_DELSECOND;
		peer->stratum = pp->stratum;
		break;

	default:
		pp->leap = LEAP_NOTINSYNC;
		peer->stratum = STRATUM_UNSPEC;
	}
	pp->disp = 0;
	pp->jitter = 0;
#else /* KERNEL_PLL LOCKCLOCK */
	pp->disp = DISPERSION;
	pp->jitter = 0;
#endif /* KERNEL_PLL LOCKCLOCK */
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
}
예제 #19
0
/*
 * chronolog_receive - receive data from the serial interface
 */
static void
chronolog_receive(
	struct recvbuf *rbufp
	)
{
	struct chronolog_unit *up;
	struct refclockproc *pp;
	struct peer *peer;

	l_fp	     trtmp;	/* arrival timestamp */
	int          hours;	/* hour-of-day */
	int	     minutes;	/* minutes-past-the-hour */
	int          seconds;	/* seconds */
	int	     temp;	/* int temp */
	int          got_good;	/* got a good time flag */

	/*
	 * Initialize pointers and read the timecode and timestamp
	 */
	peer = rbufp->recv_peer;
	pp = peer->procptr;
	up = pp->unitptr;
	temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);

	if (temp == 0) {
		if (up->tcswitch == 0) {
			up->tcswitch = 1;
			up->laststamp = trtmp;
		} else
		    up->tcswitch = 0;
		return;
	}
	pp->lencode = temp;
	pp->lastrec = up->laststamp;
	up->laststamp = trtmp;
	up->tcswitch = 1;

#ifdef DEBUG
	if (debug)
		printf("chronolog: timecode %d %s\n", pp->lencode,
		    pp->a_lastcode);
#endif

	/*
	 * We get down to business. Check the timecode format and decode
	 * its contents. This code uses the first character to see whether
	 * we're looking at a date or a time.  We store data data across
	 * calls since it is transmitted a few seconds ahead of the
	 * timestamp.
	 */
	got_good=0;
	if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day))
	{
	    /*
	     * Y2K convert the 2-digit year
	     */
	    up->year = up->year >= 69 ? up->year : up->year + 100;
	    return;
	}
	if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d",
		   &hours,&minutes,&seconds) == 3)
	{
#ifdef GET_LOCALTIME
	    struct tm  local;
	    struct tm *gmtp;
	    time_t     unixtime;
	    int        adjyear;
	    int        adjmon;

	    /*
	     * Convert to GMT for sites that distribute localtime.  This
             * means we have to do Y2K conversion on the 2-digit year;
	     * otherwise, we get the time wrong.
	     */
	    
	    memset(&local, 0, sizeof(local));

	    local.tm_year  = up->year;
	    local.tm_mon   = up->month-1;
	    local.tm_mday  = up->day;
	    local.tm_hour  = hours;
	    local.tm_min   = minutes;
	    local.tm_sec   = seconds;
	    local.tm_isdst = -1;

	    unixtime = mktime (&local);
	    if ((gmtp = gmtime (&unixtime)) == NULL)
	    {
		refclock_report (peer, CEVNT_FAULT);
		return;
	    }
	    adjyear = gmtp->tm_year+1900;
	    adjmon  = gmtp->tm_mon+1;
	    pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
	    pp->hour   = gmtp->tm_hour;
	    pp->minute = gmtp->tm_min;
	    pp->second = gmtp->tm_sec;
#ifdef DEBUG
	    if (debug)
		printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
			adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
			pp->second);
#endif
	    
#else
	    /*
	     * For more rational sites distributing UTC
	     */
	    pp->day    = ymd2yd(year+1900,month,day);
	    pp->hour   = hours;
	    pp->minute = minutes;
	    pp->second = seconds;

#endif
	    got_good=1;
	}

	if (!got_good)
	    return;


	/*
	 * Process the new sample in the median filter and determine the
	 * timecode timestamp.
	 */
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	up->lasthour = (u_char)pp->hour;
}
예제 #20
0
/*
 * pst_receive - receive data from the serial interface
 */
static void
pst_receive(
	struct recvbuf *rbufp
	)
{
	register struct pstunit *up;
	struct refclockproc *pp;
	struct peer *peer;
	l_fp trtmp;
	u_long ltemp;
	char ampmchar;		/* AM/PM indicator */
	char daychar;		/* standard/daylight indicator */
	char junque[10];	/* "yy/dd/mm/" discard */
	char info[14];		/* "frdzycchhSSFT" clock info */

	/*
	 * Initialize pointers and read the timecode and timestamp
	 */
	peer = rbufp->recv_peer;
	pp = peer->procptr;
	up = pp->unitptr;
	up->lastptr += refclock_gtlin(rbufp, up->lastptr, pp->a_lastcode
	    + BMAX - 2 - up->lastptr, &trtmp);
	*up->lastptr++ = ' ';
	*up->lastptr = '\0';

	/*
	 * Note we get a buffer and timestamp for each <cr>, but only
	 * the first timestamp is retained.
	 */
	if (up->tcswitch == 0)
		pp->lastrec = trtmp;
	up->tcswitch++;
	pp->lencode = up->lastptr - pp->a_lastcode;
	if (up->tcswitch < 3)
		return;

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. If the timecode has invalid length or is not in
	 * proper format, we declare bad format and exit.
	 */
	if (pp->lencode < LENPST) {
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	/*
	 * Timecode format:
	 * "ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx"
	 */
	if (sscanf(pp->a_lastcode,
	    "%c%2d:%2d:%2d.%3ld%c %9s%3d%13s%4ld",
	    &ampmchar, &pp->hour, &pp->minute, &pp->second, &pp->nsec,
	    &daychar, junque, &pp->day, info, &ltemp) != 10) {
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	pp->nsec *= 1000000;

	/*
	 * Decode synchronization, quality and last update. If
	 * unsynchronized, set the leap bits accordingly and exit. Once
	 * synchronized, the dispersion depends only on when the clock
	 * was last heard, which depends on the time since last update,
	 * as reported by the clock.
	 */
	if (info[9] != '8')
		pp->leap = LEAP_NOTINSYNC;
	if (info[12] == 'H')
		memcpy((char *)&pp->refid, WWVHREFID, 4);
	else
		memcpy((char *)&pp->refid, WWVREFID, 4);
	if (peer->stratum <= 1)
		peer->refid = pp->refid;
	if (ltemp == 0)
		pp->lastref = pp->lastrec;
	pp->disp = PST_PHI * ltemp * 60;

	/*
	 * Process the new sample in the median filter and determine the
	 * timecode timestamp.
	 */
	if (!refclock_process(pp))
		refclock_report(peer, CEVNT_BADTIME);
	else if (peer->disp > MAXDISTANCE)
		refclock_receive(peer);
}
예제 #21
0
/*
 * arb_receive - receive data from the serial interface
 */
static void
arb_receive(
	struct recvbuf *rbufp
	)
{
	register struct arbunit *up;
	struct refclockproc *pp;
	struct peer *peer;
	l_fp trtmp;
	int temp;
	u_char	syncchar;		/* synch indicator */
	char	tbuf[BMAX];		/* temp buffer */

	/*
	 * Initialize pointers and read the timecode and timestamp
	 */
	peer = rbufp->recv_peer;
	pp = peer->procptr;
	up = pp->unitptr;
	temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp);

	/*
	 * Note we get a buffer and timestamp for both a <cr> and <lf>,
	 * but only the <cr> timestamp is retained. The program first
	 * sends a TQ and expects the echo followed by the time quality
	 * character. It then sends a B5 starting the timecode broadcast
	 * and expects the echo followed some time later by the on-time
	 * character <cr> and then the <lf> beginning the timecode
	 * itself. Finally, at the <cr> beginning the next timecode at
	 * the next second, the program sends a B0 shutting down the
	 * timecode broadcast.
	 *
	 * If flag4 is set, the program snatches the latitude, longitude
	 * and elevation and writes it to the clockstats file.
	 */
	if (temp == 0)
		return;

	pp->lastrec = up->laststamp;
	up->laststamp = trtmp;
	if (temp < 3)
		return;

	if (up->tcswitch == 0) {

		/*
		 * Collect statistics. If nothing is recogized, just
		 * ignore; sometimes the clock doesn't stop spewing
		 * timecodes for awhile after the B0 command.
		 *
		 * If flag4 is not set, send TQ, SR, B5. If flag4 is
		 * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
		 * median filter is full, send B0.
		 */
		if (!strncmp(tbuf, "TQ", 2)) {
			up->qualchar = tbuf[2];
			write(pp->io.fd, "SR", 2);
			return;

		} else if (!strncmp(tbuf, "SR", 2)) {
			strlcpy(up->status, tbuf + 2,
				sizeof(up->status));
			if (pp->sloppyclockflag & CLK_FLAG4)
				write(pp->io.fd, "LA", 2);
			else
				write(pp->io.fd, COMMAND_START_BCAST, 2);
			return;

		} else if (!strncmp(tbuf, "LA", 2)) {
			strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon));
			write(pp->io.fd, "LO", 2);
			return;

		} else if (!strncmp(tbuf, "LO", 2)) {
			strlcat(up->latlon, " ", sizeof(up->latlon));
			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
			write(pp->io.fd, "LH", 2);
			return;

		} else if (!strncmp(tbuf, "LH", 2)) {
			strlcat(up->latlon, " ", sizeof(up->latlon));
			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
			write(pp->io.fd, "DB", 2);
			return;

		} else if (!strncmp(tbuf, "DB", 2)) {
			strlcat(up->latlon, " ", sizeof(up->latlon));
			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
			record_clock_stats(&peer->srcadr, up->latlon);
#ifdef DEBUG
			if (debug)
				printf("arbiter: %s\n", up->latlon);
#endif
			write(pp->io.fd, COMMAND_START_BCAST, 2);
		}
	}

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. If the timecode has valid length, but not in
	 * proper format, we declare bad format and exit. If the
	 * timecode has invalid length, which sometimes occurs when the
	 * B0 amputates the broadcast, we just quietly steal away. Note
	 * that the time quality character and receiver status string is
	 * tacked on the end for clockstats display. 
	 */
	up->tcswitch++;
	if (up->tcswitch <= 1 || temp < LENARB)
		return;

	/*
	 * Timecode format B5: "i yy ddd hh:mm:ss.000   "
	 */
	strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode));
	pp->a_lastcode[LENARB - 2] = up->qualchar;
	strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode));
	pp->lencode = strlen(pp->a_lastcode);
	syncchar = ' ';
	if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
	    &syncchar, &pp->year, &pp->day, &pp->hour,
	    &pp->minute, &pp->second) != 6) {
		refclock_report(peer, CEVNT_BADREPLY);
		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
		return;
	}

	/*
	 * We decode the clock dispersion from the time quality
	 * character.
	 */
	switch (up->qualchar) {

	    case '0':		/* locked, max accuracy */
		pp->disp = 1e-7;
		pp->lastref = pp->lastrec;
		break;

	    case '4':		/* unlock accuracy < 1 us */
		pp->disp = 1e-6;
		break;

	    case '5':		/* unlock accuracy < 10 us */
		pp->disp = 1e-5;
		break;

	    case '6':		/* unlock accuracy < 100 us */
		pp->disp = 1e-4;
		break;

	    case '7':		/* unlock accuracy < 1 ms */
		pp->disp = .001;
		break;

	    case '8':		/* unlock accuracy < 10 ms */
		pp->disp = .01;
		break;

	    case '9':		/* unlock accuracy < 100 ms */
		pp->disp = .1;
		break;

	    case 'A':		/* unlock accuracy < 1 s */
		pp->disp = 1;
		break;

	    case 'B':		/* unlock accuracy < 10 s */
		pp->disp = 10;
		break;

	    case 'F':		/* clock failure */
		pp->disp = MAXDISPERSE;
		refclock_report(peer, CEVNT_FAULT);
		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
		return;

	    default:
		pp->disp = MAXDISPERSE;
		refclock_report(peer, CEVNT_BADREPLY);
		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
		return;
	}
	if (syncchar != ' ')
		pp->leap = LEAP_NOTINSYNC;
	else
		pp->leap = LEAP_NOWARNING;

	/*
	 * Process the new sample in the median filter and determine the
	 * timecode timestamp.
	 */
	if (!refclock_process(pp))
		refclock_report(peer, CEVNT_BADTIME);
	else if (peer->disp > MAXDISTANCE)
		refclock_receive(peer);

	/* if (up->tcswitch >= MAXSTAGE) { */
	write(pp->io.fd, COMMAND_HALT_BCAST, 2);
	/* } */
}
예제 #22
0
/*
 * vme_poll - called by the transmit procedure
 */
static void
vme_poll(
	int unit,
	struct peer *peer
	)
{
	struct vmedate *tptr; 
	struct vmeunit *vme;
	l_fp tstmp;
	time_t tloc;
	struct tm *tadr;
	long ltemp;

        
 
	if (unit >= MAXUNITS) {
		msyslog(LOG_ERR, "vme_poll: unit %d invalid", unit);
		return;
	}
	if (!unitinuse[unit]) {
		msyslog(LOG_ERR, "vme_poll: unit %d not in use", unit);
		return;
	}
	vme = vmeunits[unit];        /* Here is the structure */
	vme->polls++;

	tptr = &vme->vmedata; 
        
	if ((tptr = get_gpsvme_time()) == NULL ) {
		vme_report_event(vme, CEVNT_BADREPLY);
		return;
	}

	get_systime(&vme->lastrec);
	vme->lasttime = current_time;

	/*
	 * Get VME time and convert to timestamp format. 
	 * The year must come from the system clock.
	 */
	/*
	  time(&tloc);
	  tadr = gmtime(&tloc);
	  tptr->year = (unsigned short)(tadr->tm_year + 1900);
	*/

	sprintf(vme->lastcode, 
		"%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0",
		tptr->doy, tptr->hr, tptr->mn,
		tptr->sec, tptr->frac, tptr->status);

	record_clock_stats(&(vme->peer->srcadr), vme->lastcode);
	vme->lencode = (u_short) strlen(vme->lastcode);

	vme->day =  tptr->doy;
	vme->hour =   tptr->hr;
	vme->minute =  tptr->mn;
	vme->second =  tptr->sec;
	vme->nsec =   tptr->frac * 1000;

#ifdef DEBUG
	if (debug)
	    printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n",
		   vme->day, vme->hour, vme->minute, vme->second,
		   vme->nsec, tptr->status);
#endif
	if (tptr->status ) {       /*  Status 0 is locked to ref., 1 is not */
		vme_report_event(vme, CEVNT_BADREPLY);
		return;
	}

	/*
	 * Now, compute the reference time value. Use the heavy
	 * machinery for the seconds and the millisecond field for the
	 * fraction when present. If an error in conversion to internal
	 * format is found, the program declares bad data and exits.
	 * Note that this code does not yet know how to do the years and
	 * relies on the clock-calendar chip for sanity.
	 */
	if (!clocktime(vme->day, vme->hour, vme->minute,
		       vme->second, GMT, vme->lastrec.l_ui,
		       &vme->yearstart, &vme->lastref.l_ui)) {
		vme->baddata++;
		vme_report_event(vme, CEVNT_BADTIME);
		msyslog(LOG_ERR, "refclock_gpsvme: bad data!!");
		return;
	}
	vme->lastref.l_uf = 0;
	DTOLFP(vme->nsec / 1e9, &ltemp);
	L_ADD(&vme->lastrec, &ltemp);
	tstmp = vme->lastref;

	L_SUB(&tstmp, &vme->lastrec);
	vme->coderecv++;

	L_ADD(&tstmp, &(fudgefactor[vme->unit]));
	vme->lastref = vme->lastrec;
	refclock_receive(vme->peer);
}
예제 #23
0
/*
 * hopfpci_poll - called by the transmit procedure
 */
static void
hopfpci_poll(
	int unit,
	struct peer *peer
	)
{
	struct refclockproc *pp;
	HOPFTIME m_time;

	pp = peer->procptr;

#ifndef SYS_WINNT
	if (ioctl(fd, HOPF_CLOCK_GET_UTC, &m_time) < 0)
		msyslog(LOG_ERR, "HOPF_P(%d): HOPF_CLOCK_GET_UTC: %m\n",
			unit);
#else
	GetHopfSystemTime(&m_time);
#endif
	pp->polls++;

	pp->day    = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay);
	pp->hour   = m_time.wHour;
	pp->minute = m_time.wMinute;
	pp->second = m_time.wSecond;
	pp->nsec   = m_time.wMilliseconds * 1000000;
	if (m_time.wStatus & LEWAPWAR)
		pp->leap = LEAP_ADDSECOND;
	else
		pp->leap = LEAP_NOWARNING;

	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
		 "ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d",
		 m_time.wStatus, pp->hour, pp->minute, pp->second,
		 pp->nsec / 1000000, m_time.wDay, m_time.wMonth,
		 m_time.wYear);
	pp->lencode = (u_short)strlen(pp->a_lastcode);

	get_systime(&pp->lastrec);

	/*
	 * If clock has no valid status then report error and exit
	 */
	if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) {  /* time ok? */
		refclock_report(peer, CEVNT_BADTIME);
		pp->leap = LEAP_NOTINSYNC;
		return;
	}

	/*
	 * Test if time is running on internal quarz
	 * if CLK_FLAG1 is set, sychronize even if no radio operation
	 */

	if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){
		if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
			refclock_report(peer, CEVNT_BADTIME);
			pp->leap = LEAP_NOTINSYNC;
			return;
		}
	}

	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	return;
}
예제 #24
0
static void
hopfserial_receive (
	struct recvbuf *rbufp
	)
{
	struct hopfclock_unit *up;
	struct refclockproc *pp;
	struct peer *peer;

	int		synch;	/* synchhronization indicator */
	int		DoW;	/* Dow */

	int	day, month;	/* ddd conversion */

	/*
	 * Initialize pointers and read the timecode and timestamp.
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = (struct hopfclock_unit *)pp->unitptr;

	if (up->rpt_next == 0 )
		return;


	up->rpt_next = 0; /* wait until next poll interval occur */

	pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);

	if (pp->lencode  == 0)
		return;

	sscanf(pp->a_lastcode,
#if 1
	       "%1x%1x%2d%2d%2d%2d%2d%2d",   /* ...cr,lf */
#else
	       "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
#endif
	       &synch,
	       &DoW,
	       &pp->hour,
	       &pp->minute,
	       &pp->second,
	       &day,
	       &month,
	       &pp->year);


	/*
	  Validate received values at least enough to prevent internal
	  array-bounds problems, etc.
	*/
	if((pp->hour < 0) || (pp->hour > 23) ||
	   (pp->minute < 0) || (pp->minute > 59) ||
	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
	   (day < 1) || (day > 31) ||
	   (month < 1) || (month > 12) ||
	   (pp->year < 0) || (pp->year > 99)) {
		/* Data out of range. */
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	/*
	  some preparations
	*/
	pp->day    = ymd2yd(pp->year,month,day);
	pp->leap=0;

	/* Year-2000 check! */
	/* wrap 2-digit date into 4-digit */

	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* < 98 */
	pp->year += 1900;

	/* preparation for timecode ntpq rl command ! */

#if 0
	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
		 "STATUS: %1X%1X, DATE: %02d.%02d.%04d  TIME: %02d:%02d:%02d",
		 synch,
		 DoW,
		 day,
		 month,
		 pp->year,
		 pp->hour,
		 pp->minute,
		 pp->second);

	pp->lencode = strlen(pp->a_lastcode);
	if ((synch && 0xc) == 0 ){  /* time ok? */
		refclock_report(peer, CEVNT_BADTIME);
		pp->leap = LEAP_NOTINSYNC;
		return;
	}
#endif
	/*
	 * If clock has no valid status then report error and exit
	 */
	if ((synch & HOPF_OPMODE) == HOPF_INVALID ){  /* time ok? */
		refclock_report(peer, CEVNT_BADTIME);
		pp->leap = LEAP_NOTINSYNC;
		return;
	}

	/*
	 * Test if time is running on internal quarz
	 * if CLK_FLAG1 is set, sychronize even if no radio operation
	 */

	if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){
		if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
			refclock_report(peer, CEVNT_BADTIME);
			pp->leap = LEAP_NOTINSYNC;
			return;
		}
	}


	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);

#if 0
	msyslog(LOG_ERR, " D:%x  D:%d D:%d",synch,pp->minute,pp->second);
#endif

	record_clock_stats(&peer->srcadr, pp->a_lastcode);

	return;
}
예제 #25
0
/*
 * pcf_poll - called by the transmit procedure
 */
static void
pcf_poll(
	int unit,
	struct peer *peer
	)
{
	struct refclockproc *pp;
	char buf[LENPCF];
	struct tm tm, *tp;
	time_t t;
	
	pp = peer->procptr;

	buf[0] = 0;
	if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) {
		refclock_report(peer, CEVNT_FAULT);
		return;
	}

	ZERO(tm);

	tm.tm_mday = buf[11] * 10 + buf[10];
	tm.tm_mon = buf[13] * 10 + buf[12] - 1;
	tm.tm_year = buf[15] * 10 + buf[14];
	tm.tm_hour = buf[7] * 10 + buf[6];
	tm.tm_min = buf[5] * 10 + buf[4];
	tm.tm_sec = buf[3] * 10 + buf[2];
	tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1;

	/*
	 * Y2K convert the 2-digit year
	 */
	if (tm.tm_year < 99)
		tm.tm_year += 100;
	
	t = mktime(&tm);
	if (t == (time_t) -1) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}

#if defined(__GLIBC__) && defined(_BSD_SOURCE)
	if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200)
	    || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600)
	    || tm.tm_isdst < 0) {
#ifdef DEBUG
		if (debug)
			printf ("local time zone not set to CET/CEST\n");
#endif
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
#endif

	pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm);

#if defined(_REENTRANT) || defined(_THREAD_SAFE)
	tp = gmtime_r(&t, &tm);
#else
	tp = gmtime(&t);
#endif
	if (!tp) {
		refclock_report(peer, CEVNT_FAULT);
		return;
	}

	get_systime(&pp->lastrec);
	pp->polls++;
	pp->year = tp->tm_year + 1900;
	pp->day = tp->tm_yday + 1;
	pp->hour = tp->tm_hour;
	pp->minute = tp->tm_min;
	pp->second = tp->tm_sec;
	pp->nsec = buf[16] * 31250000;
	if (buf[17] & 1)
		pp->nsec += 500000000;

#ifdef DEBUG
	if (debug)
		printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
			unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour,
			pp->minute, pp->second);
#endif

	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2))
		pp->leap = LEAP_NOTINSYNC;
	else
		pp->leap = LEAP_NOWARNING;
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
}
예제 #26
0
/*
 * local_poll - called by the transmit procedure
 *
 * LOCKCLOCK: If the kernel supports the nanokernel or microkernel
 * system calls, the leap bits are extracted from the kernel. If there
 * is a kernel error or the kernel leap bits are set to 11, the NTP leap
 * bits are set to 11 and the stratum is set to infinity. Otherwise, the
 * NTP leap bits are set to the kernel leap bits and the stratum is set
 * as fudged. This behavior does not faithfully follow the
 * specification, but is probably more appropriate in a multiple-server
 * national laboratory network.
 */
static void
local_poll(
	int unit,
	struct peer *peer
	)
{
#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
	struct timex ntv;
#endif /* KERNEL_PLL LOCKCLOCK */
	struct refclockproc *pp;

#if defined(VMS) && defined(VMS_LOCALUNIT)
	if (unit == VMS_LOCALUNIT) {
		extern void vms_local_poll(struct peer *);

		vms_local_poll(peer);
		return;
	}
#endif /* VMS && VMS_LOCALUNIT */
	pp = peer->procptr;
	pp->polls++;

	/*
	 * Ramble through the usual filtering and grooming code, which
	 * is essentially a no-op and included mostly for pretty
	 * billboards. We allow a one-time time adjustment using fudge
	 * time1 (s) and a continuous frequency adjustment using fudge
	 * time 2 (ppm).
	 */
	get_systime(&pp->lastrec);
	pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time -
	    poll_time);
	poll_time = current_time;
	refclock_process_offset(pp, pp->lastrec, pp->lastrec,
	    pp->fudgetime1);

	/*
	 * If another process is disciplining the system clock, we set
	 * the leap bits and quality indicators from the kernel.
	 */
#if defined(KERNEL_PLL) && defined(LOCKCLOCK)
	memset(&ntv,  0, sizeof ntv);
	switch (ntp_adjtime(&ntv)) {
	case TIME_OK:
		pp->leap = LEAP_NOWARNING;
		peer->stratum = pp->stratum;
		break;

	case TIME_INS:
		pp->leap = LEAP_ADDSECOND;
		peer->stratum = pp->stratum;
		break;

	case TIME_DEL:
		pp->leap = LEAP_DELSECOND;
		peer->stratum = pp->stratum;
		break;

	default:
		pp->leap = LEAP_NOTINSYNC;
		peer->stratum = STRATUM_UNSPEC;
	}
	pp->disp = 0;
	pp->jitter = 0;
#else /* KERNEL_PLL LOCKCLOCK */
	pp->leap = LEAP_NOWARNING;
	pp->disp = DISPERSION;
	pp->jitter = 0;
#endif /* KERNEL_PLL LOCKCLOCK */
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
	pp->fudgetime1 = 0;
}
예제 #27
0
/*
 * tpro_poll - called by the transmit procedure
 */
static void
tpro_poll(
	int unit,
	struct peer *peer
	)
{
	register struct tprounit *up;
	struct refclockproc *pp;
	struct tproval *tp;

	/*
	 * This is the main routine. It snatches the time from the TPRO
	 * board and tacks on a local timestamp.
	 */
	pp = peer->procptr;
	up = pp->unitptr;

	tp = &up->tprodata;
	if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) {
		refclock_report(peer, CEVNT_FAULT);
		return;
	}
	get_systime(&pp->lastrec);
	pp->polls++;

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. If the timecode has invalid length or is not in
	 * proper format, we declare bad format and exit. Note: we
	 * can't use the sec/usec conversion produced by the driver,
	 * since the year may be suspect. All format error checking is
	 * done by the snprintf() and sscanf() routines.
	 *
	 * Note that the refclockproc usec member has now become nsec.
	 * We could either multiply the read-in usec value by 1000 or
	 * we could pad the written string appropriately and read the
	 * resulting value in already scaled.
	 */
	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
		 "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
		 tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1,
		 tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100,
		 tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1,
		 tp->status);
	pp->lencode = strlen(pp->a_lastcode);
#ifdef DEBUG
	if (debug)
		printf("tpro: time %s timecode %d %s\n",
		   ulfptoa(&pp->lastrec, 6), pp->lencode,
		   pp->a_lastcode);
#endif
	if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day,
	    &pp->hour, &pp->minute, &pp->second, &pp->nsec)
	    != 5) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->nsec *= 1000;	/* Convert usec to nsec */
	if (!tp->status & 0x3)
		pp->leap = LEAP_NOTINSYNC;
	else
		pp->leap = LEAP_NOWARNING;
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	if (pp->coderecv == pp->codeproc) {
		refclock_report(peer, CEVNT_TIMEOUT);
		return;
	}
	pp->lastref = pp->lastrec;
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	refclock_receive(peer);
}
예제 #28
0
/* psc_poll:  read, decode, and record device time */
static void
psc_poll(
    int		unit,
    struct peer	*peer
    )
{
    struct refclockproc	*pp = peer->procptr;
    struct psc_unit		*up;
    unsigned			tlo, thi;
    unsigned char		status;

    up = (struct psc_unit *) pp->unitptr;
    tlo = regp[unit]->low_time;		/* latch and read first 4 bytes	*/
    thi = regp[unit]->high_time;	/* read 4 higher order bytes	*/
    status = regp[unit]->device_status;	/* read device status byte	*/

    if (!(status & PSC_SYNC_OK)) {
	refclock_report(peer, CEVNT_BADTIME);
	if (!up->msg_flag[unit]) {	/* write once to system log	*/
	    msyslog(LOG_WARNING,
		"SYNCHRONIZATION LOST on unit %1d, status %02x\n",
		unit, status);
	    up->msg_flag[unit] = 1;
	}
	return;
    }

    get_systime(&pp->lastrec);
    pp->polls++;
     
    tlo = SWAP(tlo);			/* little to big endian swap on	*/
    thi = SWAP(thi);			/* copy of data			*/
    /* convert the BCD time to broken down time used by refclockproc	*/
    pp->day	= BCD2INT3((thi & 0x0FFF0000) >> 16);
    pp->hour	= BCD2INT2((thi & 0x0000FF00) >> 8);
    pp->minute	= BCD2INT2(thi & 0x000000FF);
    pp->second	= BCD2INT2(tlo >> 24);
    /* ntp_process() in ntp_refclock.c appears to use usec as fraction of
       second in microseconds if usec is nonzero. */
    pp->nsec	= 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
	BCD2INT3(tlo & 0x00000FFF);

    snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
	     "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day,
	     pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
	     tlo);
    pp->lencode = strlen(pp->a_lastcode);

    /* compute the timecode timestamp	*/
    if (!refclock_process(pp)) {
	refclock_report(peer, CEVNT_BADTIME);
	return;
    }
    /* simulate the NTP receive and packet procedures	*/
    refclock_receive(peer);
    /* write clock statistics to file	*/
    record_clock_stats(&peer->srcadr, pp->a_lastcode);	

    /* With the first timecode beginning the day, check for a GPS
       leap second notification.      */
    if (pp->hour < up->last_hour) {
	check_leap_sec(pp, unit);
	up->msg_flag[0] = up->msg_flag[1] = 0;	/* reset flags	*/
    }
    up->last_hour = pp->hour;
}
예제 #29
0
/*
 * fg_receive - receive data from the serial interface
 */
static void
fg_receive(
        struct recvbuf *rbufp
        )
{
        struct refclockproc *pp;
	struct fgunit *up;
        struct peer *peer;
	char *bpt;

        /*
         * Initialize pointers and read the timecode and timestamp
	 * We can't use gtlin function because we need bynary data in buf */

        peer = (struct peer *)rbufp->recv_srcclock;
        pp = peer->procptr;
        up = (struct fgunit *)pp->unitptr;

	/*
         * Below hug to implement receiving of status information
         */
	if(!up->pollnum)
	{
		up->pollnum++;
		return;
	}

	
	if (rbufp->recv_length < (LENFG-2))
	{
		refclock_report(peer, CEVNT_BADREPLY);
            	return; /* The reply is invalid discard it. */
	}

	/* Below I trying to find a correct reply in buffer.
	 * Sometime GPS reply located in the beginnig of buffer,
	 * sometime you can find it with some offset.
	 */

	bpt = (char *)rbufp->recv_space.X_recv_buffer;
	while(*bpt != '')
		bpt++;

#define BP2(x) ( bpt[x] & 15 )
#define BP1(x) (( bpt[x] & 240 ) >> 4)
	
        pp->year = BP1(2)*10 + BP2(2);
	
	if(pp->year == 94)
	{
		refclock_report(peer, CEVNT_BADREPLY);
		if(!fg_init(pp->io.fd))
			refclock_report(peer, CEVNT_FAULT);
            	return;
		 /* GPS is just powered up. The date is invalid -
		 discarding it. Initilize GPS one more time */
		/* Sorry - this driver will broken in 2094 ;) */
	}	
	
	if (pp->year < 99)
                pp->year += 100;

        pp->year +=  1900;
        pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);

/*
   After Jan, 10 2000 Forum Graphic GPS receiver had a very strange
   benahour. It doubles day number for an hours in replys after 10:10:10 UTC
   and doubles min every hour at HH:10:ss for a minute.
   Hope it is a problem of my unit only and not a Y2K problem of FG GPS. 
   Below small code to avoid such situation.
*/
	if(up->y2kwarn > 10)
        	pp->hour = BP1(6)*10 + BP2(6);
	else
        	pp->hour = BP1(5)*10 + BP2(5);

	if((up->y2kwarn > 10) && (pp->hour == 10))
	{
        	pp->minute = BP1(7)*10 + BP2(7);
        	pp->second = BP1(8)*10 + BP2(8);
        	pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000;
        	pp->nsec += BP1(10) * 1000;
	} else {
        	pp->hour = BP1(5)*10 + BP2(5);
        	pp->minute = BP1(6)*10 + BP2(6);
        	pp->second = BP1(7)*10 + BP2(7);
        	pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000;
        	pp->nsec += BP1(9) * 1000;
	}
        
	if((pp->hour == 10) && (pp->minute == 10))
	{
		up->y2kwarn++;
	}

	sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second);
	pp->lencode = strlen(pp->a_lastcode);
        /*get_systime(&pp->lastrec);*/

#ifdef DEBUG
        if (debug)
                printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
                         pp->year, pp->day, pp->hour, pp->minute, pp->second);
#endif

        if (peer->stratum <= 1)
                peer->refid = pp->refid;
        pp->disp =  (10e-6);
	pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */
	/* pp->leap = LEAP_NOWARNING; */

        /*
         * Process the new sample in the median filter and determine the
         * timecode timestamp.
         */

        if (!refclock_process(pp))
                refclock_report(peer, CEVNT_BADTIME);
        pp->lastref = pp->lastrec;
	refclock_receive(peer);
	return;
}
예제 #30
0
static void
neoclock4x_receive(struct recvbuf *rbufp)
{
  struct neoclock4x_unit *up;
  struct refclockproc *pp;
  struct peer *peer;
  unsigned long calc_utc;
  int day;
  int month;	/* ddd conversion */
  int c;
  int dsec;
  unsigned char calc_chksum;
  int recv_chksum;

  peer = rbufp->recv_peer;
  pp = peer->procptr;
  up = pp->unitptr;

  /* wait till poll interval is reached */
  if(0 == up->recvnow)
    return;

  /* reset poll interval flag */
  up->recvnow = 0;

  /* read last received timecode */
  pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
  pp->leap = LEAP_NOWARNING;

  if(NEOCLOCK4X_TIMECODELEN != pp->lencode)
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s",
		up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode);
      refclock_report(peer, CEVNT_BADREPLY);
      return;
    }

  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2);

  /* calculate checksum */
  calc_chksum = 0;
  for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++)
    {
      calc_chksum += pp->a_lastcode[c];
    }
  if(recv_chksum != calc_chksum)
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s",
		up->unit, pp->a_lastcode);
      refclock_report(peer, CEVNT_BADREPLY);
      return;
    }

  /* Allow synchronization even is quartz clock is
   * never initialized.
   * WARNING: This is dangerous!
   */
  up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS];
  if(0==(pp->sloppyclockflag & CLK_FLAG2))
    {
      if('I' != up->quarzstatus)
	{
	  NLOG(NLOG_CLOCKEVENT)
	    msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s",
		    up->unit, pp->a_lastcode);
	  pp->leap = LEAP_NOTINSYNC;
	  refclock_report(peer, CEVNT_BADDATE);
	  return;
	}
    }
  if('I' != up->quarzstatus)
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s",
		up->unit, pp->a_lastcode);
    }

  /*
   * If NeoClock4X is not synchronized to a radio clock
   * check if we're allowed to synchronize with the quartz
   * clock.
   */
  up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE];
  if(0==(pp->sloppyclockflag & CLK_FLAG2))
    {
      if('A' != up->timesource)
	{
	  /* not allowed to sync with quartz clock */
	  if(0==(pp->sloppyclockflag & CLK_FLAG1))
	    {
	      refclock_report(peer, CEVNT_BADTIME);
	      pp->leap = LEAP_NOTINSYNC;
	      return;
	    }
	}
    }

  /* this should only used when first install is done */
  if(pp->sloppyclockflag & CLK_FLAG4)
    {
      msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s",
	      up->unit, pp->a_lastcode);
    }

  /* 123456789012345678901234567890123456789012345 */
  /* S/N123456DCF1004021010001202ASX1213CR\r\n */

  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2);
#if defined(NTP_PRE_420)
  pp->msec = dsec * 10; /* convert 1/100s from neoclock to real miliseconds */
#else
  pp->nsec = dsec * 10 * NSEC_TO_MILLI; /* convert 1/100s from neoclock to nanoseconds */
#endif

  memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3);
  up->radiosignal[3] = 0;
  memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6);
  up->serial[6] = 0;
  up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS];
  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2);
  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2);

  /*
    Validate received values at least enough to prevent internal
    array-bounds problems, etc.
  */
  if((pp->hour < 0) || (pp->hour > 23) ||
     (pp->minute < 0) || (pp->minute > 59) ||
     (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
     (day < 1) || (day > 31) ||
     (month < 1) || (month > 12) ||
     (pp->year < 0) || (pp->year > 99)) {
    /* Data out of range. */
    NLOG(NLOG_CLOCKEVENT)
      msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s",
	      up->unit, pp->a_lastcode);
    refclock_report(peer, CEVNT_BADDATE);
    return;
  }

  /* Year-2000 check not needed anymore. Same problem
   * will arise at 2099 but what should we do...?
   *
   * wrap 2-digit date into 4-digit
   *
   * if(pp->year < YEAR_PIVOT)
   * {
   *   pp->year += 100;
   * }
  */
  pp->year += 2000;

  /* adjust NeoClock4X local time to UTC */
  calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second);
  calc_utc -= 3600;
  /* adjust NeoClock4X daylight saving time if needed */
  if('S' == up->dststatus)
    calc_utc -= 3600;
  neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second);

  /*
    some preparations
  */
  pp->day = ymd2yd(pp->year, month, day);
  pp->leap = 0;

  if(pp->sloppyclockflag & CLK_FLAG4)
    {
      msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld",
	      up->unit,
	      pp->year, month, day,
	      pp->hour, pp->minute, pp->second,
#if defined(NTP_PRE_420)
              pp->msec
#else
              pp->nsec/NSEC_TO_MILLI
#endif
              );
    }

  up->utc_year   = pp->year;
  up->utc_month  = month;
  up->utc_day    = day;
  up->utc_hour   = pp->hour;
  up->utc_minute = pp->minute;
  up->utc_second = pp->second;
#if defined(NTP_PRE_420)
  up->utc_msec   = pp->msec;
#else
  up->utc_msec   = pp->nsec/NSEC_TO_MILLI;
#endif

  if(!refclock_process(pp))
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit);
      refclock_report(peer, CEVNT_FAULT);
      return;
    }
  refclock_receive(peer);

  /* report good status */
  refclock_report(peer, CEVNT_NOMINAL);

  record_clock_stats(&peer->srcadr, pp->a_lastcode);
}