Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
/*
 * as2201__receive - receive data from the serial interface
 */
static void
as2201_receive(
	struct recvbuf *rbufp
	)
{
	register struct as2201unit *up;
	struct refclockproc *pp;
	struct peer *peer;
	l_fp trtmp;
	size_t octets;

	/*
	 * Initialize pointers and read the timecode and timestamp.
	 */
	peer = rbufp->recv_peer;
	pp = peer->procptr;
	up = pp->unitptr;
	pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
#ifdef DEBUG
	if (debug)
	    printf("gps: timecode %d %d %s\n",
		   up->linect, pp->lencode, pp->a_lastcode);
#endif
	if (pp->lencode == 0)
	    return;

	/*
	 * If linect is greater than zero, we must be in the middle of a
	 * statistics operation, so simply tack the received data at the
	 * end of the statistics string. If not, we could either have
	 * just received the timecode itself or a decimal number
	 * indicating the number of following lines of the statistics
	 * reply. In the former case, write the accumulated statistics
	 * data to the clockstats file and continue onward to process
	 * the timecode; in the later case, save the number of lines and
	 * quietly return.
	 */
	if (pp->sloppyclockflag & CLK_FLAG2)
		pp->lastrec = trtmp;
	if (up->linect > 0) {
		up->linect--;
		if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2)
		    return;
		*up->lastptr++ = ' ';
		memcpy(up->lastptr, pp->a_lastcode, 1 + pp->lencode);
		up->lastptr += pp->lencode;
		return;
	} else {
		if (pp->lencode == 1) {
			up->linect = atoi(pp->a_lastcode);
			return;
		} else {
			record_clock_stats(&peer->srcadr, up->stats);
#ifdef DEBUG
			if (debug)
			    printf("gps: stat %s\n", up->stats);
#endif
		}
	}
	up->lastptr = up->stats;
	*up->lastptr = '\0';

	/*
	 * 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 < LENTOC) {
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	/*
	 * Timecode format: "yy:ddd:hh:mm:ss.mmm"
	 */
	if (sscanf(pp->a_lastcode, "%2d:%3d:%2d:%2d:%2d.%3ld", &pp->year,
		   &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec)
	    != 6) {
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	pp->nsec *= 1000000;

	/*
	 * Test for synchronization (this is a temporary crock).
	 */
	if (pp->a_lastcode[2] != ':')
		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);
		return;
	}

	/*
	 * If CLK_FLAG4 is set, initialize the statistics buffer and
	 * send the next command. If not, simply write the timecode to
	 * the clockstats file.
	 */
	if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2)
	    return;
	memcpy(up->lastptr, pp->a_lastcode, pp->lencode);
	up->lastptr += pp->lencode;
	if (pp->sloppyclockflag & CLK_FLAG4) {
		octets = strlen(stat_command[up->index]);
		if ((int)(up->lastptr - up->stats + 1 + octets) > SMAX - 2)
		    return;
		*up->lastptr++ = ' ';
		memcpy(up->lastptr, stat_command[up->index], octets);
		up->lastptr += octets - 1;
		*up->lastptr = '\0';
		(void)write(pp->io.fd, stat_command[up->index],
		    strlen(stat_command[up->index]));
		up->index++;
		if (*stat_command[up->index] == '\0')
			up->index = 0;
	}
}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
0
/*
 * ulink_receive - receive data from the serial interface
 */
static void
ulink_receive(
	struct recvbuf *rbufp
	)
{
	struct ulinkunit *up;
	struct refclockproc *pp;
	struct peer *peer;

	l_fp	trtmp;		/* arrival timestamp */
	int	quality;	/* quality indicator */
	int	temp;		/* int temp */
	char	syncchar;	/* synchronization indicator */
	char	leapchar;	/* leap indicator */
	char	modechar;	/* model 320 mode flag */
        char	siglchar;	/* model difference between 33x/325 */
	char	char_quality[2];	/* temp quality flag */

	/*
	 * Initialize pointers and read the timecode and timestamp
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = (struct ulinkunit *)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. 
	 */
	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("ulink: timecode %d %s\n", pp->lencode,
		    pp->a_lastcode);
#endif

	/*
	 * 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.
	 */
	syncchar = leapchar = modechar = siglchar = ' ';
	switch (pp->lencode ) {
		case LEN33X:

		/*
                 * First we check if the format is 33x or 325:
		 *   <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5 (33x)
		 *   <CR><LF>R5_1C00LYYYY+DDDUTCS HH:MM:SSL+5 (325)
		 * simply by comparing if the signal level is 'S' or 'R'
                 */

                 if (sscanf(pp->a_lastcode, "%c%*31c",
                            &siglchar) == 1) {

                    if(siglchar == SIGLCHAR325) {

       		   /*
		    * decode for a Model 325 decoder.
		    * Timecode format from January 23, 2004 datasheet is:
                    *
		    *   <CR><LF>R5_1C00LYYYY+DDDUTCS HH:MM:SSL+5
                    *
		    *   R      WWVB decodersignal readability R1 - R5
		    *   5      R1 is unreadable, R5 is best
		    *   space  a space (0x20)
		    *   1      Data bit 0, 1, M (pos mark), or ? (unknown).
		    *   C      Reception from either (C)olorado or (H)awaii 
		    *   00     Hours since last good WWVB frame sync. Will 
		    *          be 00-99
		    *   space  Space char (0x20) or (0xa5) if locked to wwvb
		    *   YYYY   Current year, 2000-2099
		    *   +      Leap year indicator. '+' if a leap year,
		    *          a space (0x20) if not.
		    *   DDD    Day of year, 000 - 365.
		    *   UTC    Timezone (always 'UTC').
		    *   S      Daylight savings indicator
		    *             S - standard time (STD) in effect
		    *             O - during STD to DST day 0000-2400
		    *             D - daylight savings time (DST) in effect
		    *             I - during DST to STD day 0000-2400
		    *   space  Space character (0x20)
		    *   HH     Hours 00-23
		    *   :      This is the REAL in sync indicator (: = insync)	
		    *   MM     Minutes 00-59
		    *   :      : = in sync ? = NOT in sync
		    *   SS     Seconds 00-59
		    *   L      Leap second flag. Changes from space (0x20)
		    *          to 'I' or 'D' during month preceding leap
		    *          second adjustment. (I)nsert or (D)elete
		    *   +5     UT1 correction (sign + digit ))
		    */

   		       if (sscanf(pp->a_lastcode, 
                          "%*2c %*2c%2c%*c%4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c",
   		          char_quality, &pp->year, &pp->day, 
                          &pp->hour, &syncchar, &pp->minute, &pp->second, 
                          &leapchar) == 8) { 
   		
   			  if (char_quality[0] == '0') {
   				quality = 0;
   			  } else if (char_quality[0] == '0') {
   				quality = (char_quality[1] & 0x0f);
   			  } else  {
   				quality = 99;
   			  }

   		          if (leapchar == 'I' ) leapchar = '+';
   		          if (leapchar == 'D' ) leapchar = '-';

		          /*
		          #ifdef DEBUG
		          if (debug) {
		             printf("ulink: char_quality %c %c\n", 
                                    char_quality[0], char_quality[1]);
			     printf("ulink: quality %d\n", quality);
			     printf("ulink: syncchar %x\n", syncchar);
			     printf("ulink: leapchar %x\n", leapchar);
                          }
                          #endif
                          */

                       }
		
                    } 
                    if(siglchar == SIGLCHAR33x) {
                
		   /*
		    * We got a Model 33X decoder.
		    * Timecode format from January 29, 2001 datasheet is:
		    *   <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5
		    *   S      WWVB decoder sync indicator. S for in-sync(?)
		    *          or N for noisy signal.
		    *   9+     RF signal level in S-units, 0-9 followed by
		    *          a space (0x20). The space turns to '+' if the
		    *          level is over 9.
		    *   D      Data bit 0, 1, 2 (position mark), or
		    *          3 (unknown).
		    *   space  Space character (0x20)
		    *   00     Hours since last good WWVB frame sync. Will 
		    *          be 00-23 hrs, or '1d' to '7d'. Will be 'Lk'
                    *          if currently in sync. 
		    *   space  Space character (0x20)
		    *   YYYY   Current year, 1990-2089
		    *   +      Leap year indicator. '+' if a leap year,
		    *          a space (0x20) if not.
		    *   DDD    Day of year, 001 - 366.
		    *   UTC    Timezone (always 'UTC').
		    *   S      Daylight savings indicator
		    *             S - standard time (STD) in effect
		    *             O - during STD to DST day 0000-2400
		    *             D - daylight savings time (DST) in effect
		    *             I - during DST to STD day 0000-2400
		    *   space  Space character (0x20)
		    *   HH     Hours 00-23
		    *   :      This is the REAL in sync indicator (: = insync)	
		    *   MM     Minutes 00-59
		    *   :      : = in sync ? = NOT in sync
		    *   SS     Seconds 00-59
		    *   L      Leap second flag. Changes from space (0x20)
		    *          to '+' or '-' during month preceding leap
		    *          second adjustment.
		    *   +5     UT1 correction (sign + digit ))
		    */

		       if (sscanf(pp->a_lastcode, 
                           "%*4c %2c %4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c",
		           char_quality, &pp->year, &pp->day, 
                           &pp->hour, &syncchar, &pp->minute, &pp->second, 
                           &leapchar) == 8) { 
		
			   if (char_quality[0] == 'L') {
				quality = 0;
			   } else if (char_quality[0] == '0') {
				quality = (char_quality[1] & 0x0f);
			   } else  {
				quality = 99;
		           }
	
                           /*
                           #ifdef DEBUG
         		   if (debug) {
         			printf("ulink: char_quality %c %c\n", 
                                        char_quality[0], char_quality[1]);
         			printf("ulink: quality %d\n", quality);
         			printf("ulink: syncchar %x\n", syncchar);
         			printf("ulink: leapchar %x\n", leapchar);
                           }
                           #endif
                           */

		        }
                    }
		    break;
		}

		case LEN320:

	        /*
		 * Model 320 Decoder
		 * The timecode format is:
		 *
		 *  <cr><lf>SQRYYYYDDD+HH:MM:SS.mmLT<cr>
		 *
		 * where:
		 *
		 * S = 'S' -- sync'd in last hour,
		 *     '0'-'9' - hours x 10 since last update,
		 *     '?' -- not in sync
		 * Q = Number of correlating time-frames, from 0 to 5
		 * R = 'R' -- reception in progress,
		 *     'N' -- Noisy reception,
		 *     ' ' -- standby mode
		 * YYYY = year from 1990 to 2089
		 * DDD = current day from 1 to 366
		 * + = '+' if current year is a leap year, else ' '
		 * HH = UTC hour 0 to 23
		 * MM = Minutes of current hour from 0 to 59
		 * SS = Seconds of current minute from 0 to 59
		 * mm = 10's milliseconds of the current second from 00 to 99
		 * L  = Leap second pending at end of month
		 *     'I' = insert, 'D'= delete
		 * T  = DST <-> STD transition indicators
		 *
        	 */

		if (sscanf(pp->a_lastcode, "%c%1d%c%4d%3d%*c%2d:%2d:%2d.%2ld%c",
	               &syncchar, &quality, &modechar, &pp->year, &pp->day,
        	       &pp->hour, &pp->minute, &pp->second,
			&pp->nsec, &leapchar) == 10) {
		pp->nsec *= 10000000; /* M320 returns 10's of msecs */
		if (leapchar == 'I' ) leapchar = '+';
		if (leapchar == 'D' ) leapchar = '-';
		if (syncchar != '?' ) syncchar = ':';

 		break;
		}

		default:
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	/*
	 * Decode quality indicator
	 * For the 325 & 33x series, the lower the number the "better" 
	 * the time is. I used the dispersion as the measure of time 
	 * quality. The quality indicator in the 320 is the number of 
	 * correlating time frames (the more the better)
	 */

	/* 
	 * The spec sheet for the 325 & 33x series states the clock will
	 * maintain +/-0.002 seconds accuracy when locked to WWVB. This 
	 * is indicated by 'Lk' in the quality portion of the incoming 
	 * string. When not in lock, a drift of +/-0.015 seconds should 
	 * be allowed for.
	 * With the quality indicator decoding scheme above, the 'Lk' 
	 * condition will produce a quality value of 0. If the quality 
	 * indicator starts with '0' then the second character is the 
	 * number of hours since we were last locked. If the first 
	 * character is anything other than 'L' or '0' then we have been 
	 * out of lock for more than 9 hours so we assume the worst and 
	 * force a quality value that selects the 'default' maximum 
	 * dispersion. The dispersion values below are what came with the
	 * driver. They're not unreasonable so they've not been changed.
	 */

	if (pp->lencode == LEN33X) {
		switch (quality) {
			case 0 :
				pp->disp=.002;
				break;
			case 1 :
				pp->disp=.02;
				break;
			case 2 :
				pp->disp=.04;
				break;
			case 3 :
				pp->disp=.08;
				break;
			default:
				pp->disp=MAXDISPERSE;
				break;
		}
	} else {
		switch (quality) {
			case 5 :
				pp->disp=.002;
				break;
			case 4 :
				pp->disp=.02;
				break;
			case 3 :
				pp->disp=.04;
				break;
			case 2 :
				pp->disp=.08;
				break;
			case 1 :
				pp->disp=.16;
				break;
			default:
				pp->disp=MAXDISPERSE;
				break;
		}

	}

	/*
	 * Decode synchronization, and leap characters. If
	 * unsynchronized, set the leap bits accordingly and exit.
	 * Otherwise, set the leap bits according to the leap character.
	 */

	if (syncchar != ':')
		pp->leap = LEAP_NOTINSYNC;
	else if (leapchar == '+')
		pp->leap = LEAP_ADDSECOND;
	else if (leapchar == '-')
		pp->leap = LEAP_DELSECOND;
	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);
	}

}
Ejemplo n.º 7
0
/*
 * true_receive - receive data from the serial interface on a clock
 */
static void
true_receive(
	struct recvbuf *rbufp
	)
{
	register struct true_unit *up;
	struct refclockproc *pp;
	struct peer *peer;
	u_short new_station;
	char synced;
	int i;
	int lat, lon, off;	/* GOES Satellite position */
        /* Use these variable to hold data until we decide its worth keeping */
        char    rd_lastcode[BMAX];
        l_fp    rd_tmp;
        u_short rd_lencode;

	/*
	 * Get the clock this applies to and pointers to the data.
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = (struct true_unit *)pp->unitptr;

	/*
	 * Read clock output.  Automatically handles STREAMS, CLKLDISC.
	 */
        rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
        rd_lastcode[rd_lencode] = '\0';

	/*
	 * There is a case where <cr><lf> generates 2 timestamps.
	 */
        if (rd_lencode == 0)
            return;
        pp->lencode = rd_lencode;
        strcpy(pp->a_lastcode, rd_lastcode);
        pp->lastrec = rd_tmp;
	true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode);

	up->pollcnt = 2;
	record_clock_stats(&peer->srcadr, pp->a_lastcode);

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. This code decodes a multitude of different
	 * clock messages. Timecodes are processed if needed. All replies
	 * will be run through the state machine to tweak driver options
	 * and program the clock.
	 */

	/*
	 * Clock misunderstood our last command?
	 */
	if (pp->a_lastcode[0] == '?' ||
	    strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
		true_doevent(peer, e_Huh);
		return;
	}

	/*
	 * Timecode: "nnnnn+nnn-nnn"
	 * (from GOES clock when asked about satellite position)
	 */
	if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
	    (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
	    sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
	    ) {
		const char *label = "Botch!";

		/*
		 * This is less than perfect.  Call the (satellite)
		 * either EAST or WEST and adjust slop accodingly
		 * Perfectionists would recalculate the exact delay
		 * and adjust accordingly...
		 */
		if (lon > 7000 && lon < 14000) {
			if (lon < 10000) {
				new_station = GOES_EAST;
				label = "EAST";
			} else {
				new_station = GOES_WEST;
				label = "WEST";
			}
				
			if (new_station != up->station) {
				double dtemp;

				dtemp = pp->fudgetime1;
				pp->fudgetime1 = pp->fudgetime2;
				pp->fudgetime2 = dtemp;
				up->station = new_station;
			}
		}
		else {
			/*refclock_report(peer, CEVNT_BADREPLY);*/
			label = "UNKNOWN";
		}
		true_debug(peer, "GOES: station %s\n", label);
		true_doevent(peer, e_Satellite);
		return;
	}

	/*
	 * Timecode: "Fnn"
	 * (from TM/TMD clock when it wants to tell us what it's up to.)
	 */
	if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
		switch (i) {
		    case 50:
			true_doevent(peer, e_F50);
			break;
		    case 51:
			true_doevent(peer, e_F51);
			break;
		    default:
			true_debug(peer, "got F%02d - ignoring\n", i);
			break;
		}
		return;
	}

	/*
	 * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
	 * (from a TM/TMD/XL clock during initialization.)
	 */
	if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
	    strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
		true_doevent(peer, e_F18);
		NLOG(NLOG_CLOCKSTATUS) {
			msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
		}
		return;
	}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
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);
	/* } */
}
Ejemplo n.º 10
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);
}
Ejemplo n.º 11
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);
	}
}