Пример #1
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);
	}
}
Пример #2
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);
}
Пример #3
0
time_t
parse_to_unixtime(
	register clocktime_t   *clock_time,
	register unsigned long *cvtrtc
	)
{
#define SETRTC(_X_)	{ if (cvtrtc) *cvtrtc = (_X_); }
	static int days_of_month[] =
	{
		0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
	};
	register int i;
	time_t t;

	if (clock_time->utctime)
	    return clock_time->utctime;	/* if the conversion routine gets it right away - why not */

	if ( clock_time->year < YEAR_PIVOT )			/* Y2KFixes [ */
	    clock_time->year += 100;	/* convert 20xx%100 to 20xx-1900 */
	if ( clock_time->year < YEAR_BREAK )	/* expand to full four-digits */
	    clock_time->year += 1900;

	if (clock_time->year < 1970 )				/* Y2KFixes ] */
	{
		SETRTC(CVT_FAIL|CVT_BADDATE);
		return -1;
	}

	/*
	 * sorry, slow section here - but it's not time critical anyway
	 */
	t = julian0(clock_time->year) - julian0(1970);		/* Y2kFixes */
				/* month */
	if (clock_time->month <= 0 || clock_time->month > 12)
	{
		SETRTC(CVT_FAIL|CVT_BADDATE);
		return -1;		/* bad month */
	}

#if 0								/* Y2KFixes */
				/* adjust leap year */
	if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
	    t--;
#else								/* Y2KFixes [ */
	if ( clock_time->month >= 3  &&  isleap_4(clock_time->year) )
	    t++;		/* add one more if within leap year */
#endif								/* Y2KFixes ] */

	for (i = 1; i < clock_time->month; i++)
	{
		t += days_of_month[i];
	}
				/* day */
	if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
			       clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
	{
		SETRTC(CVT_FAIL|CVT_BADDATE);
		return -1;		/* bad day */
	}

	t += clock_time->day - 1;
				/* hour */
	if (clock_time->hour < 0 || clock_time->hour >= 24)
	{
		SETRTC(CVT_FAIL|CVT_BADTIME);
		return -1;		/* bad hour */
	}

	t = t*24 + clock_time->hour;

				/* min */
	if (clock_time->minute < 0 || clock_time->minute > 59)
	{
		SETRTC(CVT_FAIL|CVT_BADTIME);
		return -1;		/* bad min */
	}

	t = t*60 + clock_time->minute;
				/* sec */

	if (clock_time->second < 0 || clock_time->second > 60)	/* allow for LEAPs */
	{
		SETRTC(CVT_FAIL|CVT_BADTIME);
		return -1;		/* bad sec */
	}

	t  = t*60 + clock_time->second;

	t += clock_time->utcoffset;	/* warp to UTC */

				/* done */

	clock_time->utctime = t;		/* documentray only */

	return t;
}