Пример #1
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;
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
0
void
test_LeapYearFebruary(void) {
	TEST_ASSERT_EQUAL(31 + 20, ymd2yd(2012, 2, 20)); //2012-02-20 (leap year)
}
Пример #5
0
void
test_LeapYearDecember(void) {
	// 2012-12-31
	int expected = 31+29+31+30+31+30+31+31+30+31+30+31;
	TEST_ASSERT_EQUAL(expected, ymd2yd(2012, 12, 31));
}
Пример #6
0
void
test_NonLeapYearFebruary(void) {
	TEST_ASSERT_EQUAL(31 + 20, ymd2yd(2010, 2, 20)); //2010-02-20
}
Пример #7
0
void
test_NonLeapYearJune(void) {
	int expected = 31+28+31+30+31+18; // 18 June non-leap year
	TEST_ASSERT_EQUAL(expected, ymd2yd(2011, 6, 18));
}
Пример #8
0
/*
 * wwvb_receive - receive data from the serial interface
 */
static void
wwvb_receive(
	struct recvbuf *rbufp
	)
{
	struct wwvbunit *up;
	struct refclockproc *pp;
	struct peer *peer;

	l_fp	trtmp;		/* arrival timestamp */
	int	tz;		/* time zone */
	int	day, month;	/* ddd conversion */
	int	temp;		/* int temp */
	char	syncchar;	/* synchronization indicator */
	char	qualchar;	/* quality indicator */
	char	leapchar;	/* leap indicator */
	char	dstchar;	/* daylight/standard indicator */
	char	tmpchar;	/* trashbin */

	/*
	 * 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);

	/*
	 * Note we get a buffer and timestamp for both a <cr> and <lf>,
	 * but only the <cr> timestamp is retained. Note: in format 0 on
	 * a Netclock/2 or upgraded 8170 the start bit is delayed 100
	 * +-50 us relative to the pps; however, on an unmodified 8170
	 * the start bit can be delayed up to 10 ms. In format 2 the
	 * reading precision is only to the millisecond. Thus, unless
	 * you have a PPS gadget and don't have to have the year, format
	 * 0 provides the lowest jitter.
	 * Save the timestamp of each <CR> in up->laststamp.  Lines with
	 * no characters occur for every <LF>, and for some <CR>s when
	 * format 0 is used. Format 0 starts and ends each cycle with a
	 * <CR><LF> pair, format 2 starts each cycle with its only pair.
	 * The preceding <CR> is the on-time character for both formats.
	 * The timestamp provided with non-empty lines corresponds to
	 * the <CR> following the timecode, which is ultimately not used
	 * with format 0 and is used for the following timecode for
	 * format 2.
	 */
	if (temp == 0) {
		if (up->prev_eol_cr) {
			DPRINTF(2, ("wwvb: <LF> @ %s\n",
				    prettydate(&trtmp)));
		} else {
			up->laststamp = trtmp;
			DPRINTF(2, ("wwvb: <CR> @ %s\n", 
				    prettydate(&trtmp)));
		}
		up->prev_eol_cr = !up->prev_eol_cr;
		return;
	}
	pp->lencode = temp;
	pp->lastrec = up->laststamp;
	up->laststamp = trtmp;
	up->prev_eol_cr = TRUE;
	DPRINTF(2, ("wwvb: code @ %s\n"
		    "       using %s minus one char\n",
		    prettydate(&trtmp), prettydate(&pp->lastrec)));
	if (L_ISZERO(&pp->lastrec))
		return;

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. This code uses the timecode length to determine
	 * format 0, 2 or 3. If the timecode has invalid length or is
	 * not in proper format, we declare bad format and exit.
	 */
	syncchar = qualchar = leapchar = dstchar = ' ';
	tz = 0;
	switch (pp->lencode) {

	case LENWWVB0:

		/*
		 * Timecode format 0: "I  ddd hh:mm:ss DTZ=nn"
		 */
		if (sscanf(pp->a_lastcode,
		    "%c %3d %2d:%2d:%2d%c%cTZ=%2d",
		    &syncchar, &pp->day, &pp->hour, &pp->minute,
		    &pp->second, &tmpchar, &dstchar, &tz) == 8) {
			pp->nsec = 0;
			break;
		}
		goto bad_format;

	case LENWWVB2:

		/*
		 * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */
		if (sscanf(pp->a_lastcode,
		    "%c%c %2d %3d %2d:%2d:%2d.%3ld %c",
		    &syncchar, &qualchar, &pp->year, &pp->day,
		    &pp->hour, &pp->minute, &pp->second, &pp->nsec,
		    &leapchar) == 9) {
			pp->nsec *= 1000000;
			break;
		}
		goto bad_format;

	case LENWWVB3:

		/*
		 * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#"
		 * WARNING: Undocumented, and the on-time character # is
		 * not yet handled correctly by this driver.  It may be
		 * as simple as compensating for an additional 1/960 s.
		 */
		if (sscanf(pp->a_lastcode,
		    "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c",
		    &syncchar, &pp->year, &month, &day, &pp->hour,
		    &pp->minute, &pp->second, &dstchar, &leapchar) == 8)
		    {
			pp->day = ymd2yd(pp->year, month, day);
			pp->nsec = 0;
			break;
		}
		goto bad_format;

	default:
	bad_format:

		/*
		 * Unknown format: If dumping internal table, record
		 * stats; otherwise, declare bad format.
		 */
		if (up->linect > 0) {
			up->linect--;
			record_clock_stats(&peer->srcadr,
			    pp->a_lastcode);
		} else {
			refclock_report(peer, CEVNT_BADREPLY);
		}
		return;
	}

	/*
	 * Decode synchronization, quality and leap characters. If
	 * unsynchronized, set the leap bits accordingly and exit.
	 * Otherwise, set the leap bits according to the leap character.
	 * Once synchronized, the dispersion depends only on the
	 * quality character.
	 */
	switch (qualchar) {

	    case ' ':
		pp->disp = .001;
		pp->lastref = pp->lastrec;
		break;

	    case 'A':
		pp->disp = .01;
		break;

	    case 'B':
		pp->disp = .1;
		break;

	    case 'C':
		pp->disp = .5;
		break;

	    case 'D':
		pp->disp = MAXDISPERSE;
		break;

	    default:
		pp->disp = MAXDISPERSE;
		refclock_report(peer, CEVNT_BADREPLY);
		break;
	}
	if (syncchar != ' ')
		pp->leap = LEAP_NOTINSYNC;
	else if (leapchar == 'L')
		pp->leap = LEAP_ADDSECOND;
	else
		pp->leap = LEAP_NOWARNING;

	/*
	 * Process the new sample in the median filter and determine the
	 * timecode timestamp, but only if the PPS is not in control.
	 */
#ifdef HAVE_PPSAPI
	up->tcount++;
	if (peer->flags & FLAG_PPS)
		return;

#endif /* HAVE_PPSAPI */
	if (!refclock_process_f(pp, pp->fudgetime2))
		refclock_report(peer, CEVNT_BADTIME);
}
Пример #9
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);
}
Пример #10
0
/*
 * acts_timecode - identify the service and parse the timecode message
 */
void
acts_timecode(
	struct peer *peer,	/* peer structure pointer */
	char	*str		/* timecode string */
	)
{
	struct actsunit *up;
	struct refclockproc *pp;
	int	day;		/* day of the month */
	int	month;		/* month of the year */
	u_long	mjd;		/* Modified Julian Day */
	double	dut1;		/* DUT adjustment */

	u_int	dst;		/* ACTS daylight/standard time */
	u_int	leap;		/* ACTS leap indicator */
	double	msADV;		/* ACTS transmit advance (ms) */
	char	utc[10];	/* ACTS timescale */
	char	flag;		/* ACTS on-time character (* or #) */

	char	synchar;	/* WWVB synchronized indicator */
	char	qualchar;	/* WWVB quality indicator */
	char	leapchar;	/* WWVB leap indicator */
	char	dstchar;	/* WWVB daylight/savings indicator */
	int	tz;		/* WWVB timezone */

	int	leapmonth;	/* PTB/NPL month of leap */
	char	leapdir;	/* PTB/NPL leap direction */

	/*
	 * The parser selects the modem format based on the message
	 * length. Since the data are checked carefully, occasional
	 * errors due noise are forgivable.
	 */
	pp = peer->procptr;
	up = (struct actsunit *)pp->unitptr;
	pp->nsec = 0;
	switch(strlen(str)) {

	/*
	 * For USNO format on-time character '*', which is on a line by
	 * itself. Be sure a timecode has been received.
	 */
	case 1:
		if (*str == '*' && up->msgcnt > 0) 
			break;

		return;
	
	/*
	 * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
	 * UTC(NIST) *"
	 */
	case LENACTS:
		if (sscanf(str,
		    "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c",
		    &mjd, &pp->year, &month, &day, &pp->hour,
		    &pp->minute, &pp->second, &dst, &leap, &dut1,
		    &msADV, utc, &flag) != 13) {
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}

		/*
		 * Wait until ACTS has calculated the roundtrip delay.
		 * We don't need to do anything, as ACTS adjusts the
		 * on-time epoch.
		 */
		if (flag != '#')
			return;

		pp->day = ymd2yd(pp->year, month, day);
		pp->leap = LEAP_NOWARNING;
		if (leap == 1)
	    		pp->leap = LEAP_ADDSECOND;
		else if (pp->leap == 2)
	    		pp->leap = LEAP_DELSECOND;
		memcpy(&pp->refid, REFACTS, 4);
		if (up->msgcnt == 0)
			record_clock_stats(&peer->srcadr, str);
		up->msgcnt++;
		break;

	/*
	 * USNO format: "jjjjj nnn hhmmss UTC"
	 */
	case LENUSNO:
		if (sscanf(str, "%5ld %3d %2d%2d%2d %3s",
		    &mjd, &pp->day, &pp->hour, &pp->minute,
		    &pp->second, utc) != 6) {
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}

		/*
		 * Wait for the on-time character, which follows in a
		 * separate message. There is no provision for leap
		 * warning.
		 */
		pp->leap = LEAP_NOWARNING;
		memcpy(&pp->refid, REFUSNO, 4);
		if (up->msgcnt == 0)
			record_clock_stats(&peer->srcadr, str);
		up->msgcnt++;
		return;

	/*
	 * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ" 
	 */
	case LENPTB:
		if (sscanf(str,
		    "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c",
		    &pp->second, &pp->year, &month, &day, &pp->hour,
		    &pp->minute, &mjd, &dut1, &leapdir, &leapmonth,
		    &msADV, &flag) != 12) {
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
		pp->leap = LEAP_NOWARNING;
		if (leapmonth == month) {
			if (leapdir == '+')
		    		pp->leap = LEAP_ADDSECOND;
			else if (leapdir == '-')
		    		pp->leap = LEAP_DELSECOND;
		}
		pp->day = ymd2yd(pp->year, month, day);
		memcpy(&pp->refid, REFPTB, 4);
		if (up->msgcnt == 0)
			record_clock_stats(&peer->srcadr, str);
		up->msgcnt++;
		break;


	/*
	 * WWVB format 0: "I  ddd hh:mm:ss DTZ=nn"
	 */
	case LENWWVB0:
		if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d",
		    &synchar, &pp->day, &pp->hour, &pp->minute,
		    &pp->second, &dstchar, &tz) != 7) {
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
		pp->leap = LEAP_NOWARNING;
		if (synchar != ' ')
			pp->leap = LEAP_NOTINSYNC;
		memcpy(&pp->refid, REFWWVB, 4);
		if (up->msgcnt == 0)
			record_clock_stats(&peer->srcadr, str);
		up->msgcnt++;
		break;

	/*
	 * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD"
	 */
	case LENWWVB2:
		if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c",
		    &synchar, &qualchar, &pp->year, &pp->day,
		    &pp->hour, &pp->minute, &pp->second, &pp->nsec,
		    &dstchar, &leapchar, &dstchar) != 11) {
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
		pp->nsec *= 1000000;
		pp->leap = LEAP_NOWARNING;
		if (synchar != ' ')
			pp->leap = LEAP_NOTINSYNC;
		else if (leapchar == 'L')
			pp->leap = LEAP_ADDSECOND;
		memcpy(&pp->refid, REFWWVB, 4);
		if (up->msgcnt == 0)
			record_clock_stats(&peer->srcadr, str);
		up->msgcnt++;
		break;

	/*
	 * None of the above. Just forget about it and wait for the next
	 * message or timeout.
	 */
	default:
		return;
	}

	/*
	 * We have a valid timecode. The fudge time1 value is added to
	 * each sample by the main line routines. Note that in current
	 * telephone networks the propatation time can be different for
	 * each call and can reach 200 ms for some calls.
	 */
	peer->refid = pp->refid;
	pp->lastrec = up->tstamp;
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	if (up->state != S_MSG) {
		up->state = S_MSG;
		up->timer = TIMECODE;
	}
}
Пример #11
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);
}
Пример #12
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;
}
Пример #13
0
TEST(ymd2yd, LeapYearFebruary) {
	TEST_ASSERT_EQUAL(31+20, ymd2yd(2012,2,20)); //2012-02-20 (leap year)
}
Пример #14
0
TEST(ymd2yd, NonLeapYearFebruary) {
	TEST_ASSERT_EQUAL(31+20, ymd2yd(2010,2,20)); //2010-02-20
}