6 * - clock driver for hopf serial boards (GPS or DCF77)
8 * Date: 30.03.2000 Revision: 01.10
10 * latest source and further information can be found at:
11 * http://www.ATLSoft.de/ntp
19 #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
23 #include "ntp_control.h"
24 #include "ntp_refclock.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_stdlib.h"
28 #if defined HAVE_SYS_MODEM_H
29 # include <sys/modem.h>
31 # define TIOCMSET MCSETA
32 # define TIOCMGET MCGETA
33 # define TIOCM_RTS MRTS
38 # ifdef TERMIOS_NEEDS__SVID3
42 # ifdef TERMIOS_NEEDS__SVID3
47 #ifdef HAVE_SYS_IOCTL_H
48 # include <sys/ioctl.h>
52 extern int async_write(int, const void *, unsigned int);
54 #define write(fd, data, octets) async_write(fd, data, octets)
60 #define DESCRIPTION "hopf Elektronik serial clock" /* Long name */
61 #define PRECISION (-10) /* precision assumed (about 1 ms) */
62 #define REFID "hopf\0" /* reference ID */
66 #define DEVICE "/dev/hopfclock%d" /* device name and unit */
67 #define SPEED232 B9600 /* uart speed (9600 baud) */
76 #define REC_QUEUE_EMPTY 0
77 #define REC_QUEUE_FULL 1
79 #define HOPF_OPMODE 0x0C /* operation mode mask */
80 #define HOPF_INVALID 0x00 /* no time code available */
81 #define HOPF_INTERNAL 0x04 /* internal clock */
82 #define HOPF_RADIO 0x08 /* radio clock */
83 #define HOPF_RADIOHP 0x0C /* high precision radio clock */
86 * hopfclock unit control structure.
88 struct hopfclock_unit
{
89 l_fp laststamp
; /* last receive timestamp */
90 short unit
; /* NTP refclock unit number */
91 u_long polled
; /* flag to detect noreplies */
92 char leap_status
; /* leap second flag */
100 static int hopfserial_start (int, struct peer
*);
101 static void hopfserial_shutdown (int, struct peer
*);
102 static void hopfserial_receive (struct recvbuf
*);
103 static void hopfserial_poll (int, struct peer
*);
104 /* static void hopfserial_io (struct recvbuf *); */
108 struct refclock refclock_hopfser
= {
109 hopfserial_start
, /* start up driver */
110 hopfserial_shutdown
, /* shut down driver */
111 hopfserial_poll
, /* transmit poll message */
112 noentry
, /* not used */
113 noentry
, /* initialize driver (not used) */
114 noentry
, /* not used */
115 NOFLAGS
/* not used */
119 * hopfserial_start - open the devices and initialize data for processing
127 register struct hopfclock_unit
*up
;
128 struct refclockproc
*pp
;
132 (void) sprintf(gpsdev
, DEVICE
, unit
);
134 /* LDISC_STD, LDISC_RAW
135 * Open serial port. Use CLK line discipline, if available.
137 fd
= refclock_open(gpsdev
, SPEED232
, LDISC_CLK
);
140 printf("hopfSerialClock(%d) start: open %s failed\n", unit
, gpsdev
);
145 msyslog(LOG_NOTICE
, "hopfSerialClock(%d) fd: %d dev: %s", unit
, fd
,
149 * Allocate and initialize unit structure
151 up
= (struct hopfclock_unit
*) emalloc(sizeof(struct hopfclock_unit
));
154 msyslog(LOG_ERR
, "hopfSerialClock(%d) emalloc: %m",unit
);
156 printf("hopfSerialClock(%d) emalloc\n",unit
);
162 memset((char *)up
, 0, sizeof(struct hopfclock_unit
));
164 pp
->unitptr
= (caddr_t
)up
;
165 pp
->io
.clock_recv
= hopfserial_receive
;
166 pp
->io
.srcclock
= (caddr_t
)peer
;
169 if (!io_addclock(&pp
->io
)) {
171 printf("hopfSerialClock(%d) io_addclock\n",unit
);
179 * Initialize miscellaneous variables
181 pp
->clockdesc
= DESCRIPTION
;
182 peer
->precision
= PRECISION
;
183 peer
->burst
= NSTAGE
;
184 memcpy((char *)&pp
->refid
, REFID
, 4);
187 up
->unit
= (short) unit
;
194 * hopfserial_shutdown - shut down the clock
197 hopfserial_shutdown (
202 register struct hopfclock_unit
*up
;
203 struct refclockproc
*pp
;
206 up
= (struct hopfclock_unit
*)pp
->unitptr
;
207 io_closeclock(&pp
->io
);
214 * hopfserial_receive - receive data from the serial interface
219 struct recvbuf
*rbufp
222 struct hopfclock_unit
*up
;
223 struct refclockproc
*pp
;
226 int synch
; /* synchhronization indicator */
229 int day
, month
; /* ddd conversion */
232 * Initialize pointers and read the timecode and timestamp.
234 peer
= (struct peer
*)rbufp
->recv_srcclock
;
236 up
= (struct hopfclock_unit
*)pp
->unitptr
;
238 if (up
->rpt_next
== 0 )
242 up
->rpt_next
= 0; /* wait until next poll interval occur */
244 pp
->lencode
= (u_short
)refclock_gtlin(rbufp
, pp
->a_lastcode
, BMAX
, &pp
->lastrec
);
246 if (pp
->lencode
== 0)
249 sscanf(pp
->a_lastcode
,
251 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */
253 "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
266 Validate received values at least enough to prevent internal
267 array-bounds problems, etc.
269 if((pp
->hour
< 0) || (pp
->hour
> 23) ||
270 (pp
->minute
< 0) || (pp
->minute
> 59) ||
271 (pp
->second
< 0) || (pp
->second
> 60) /*Allow for leap seconds.*/ ||
272 (day
< 1) || (day
> 31) ||
273 (month
< 1) || (month
> 12) ||
274 (pp
->year
< 0) || (pp
->year
> 99)) {
275 /* Data out of range. */
276 refclock_report(peer
, CEVNT_BADREPLY
);
282 pp
->day
= ymd2yd(pp
->year
,month
,day
);
285 /* Year-2000 check! */
286 /* wrap 2-digit date into 4-digit */
288 if(pp
->year
< YEAR_PIVOT
) { pp
->year
+= 100; } /* < 98 */
291 /* preparation for timecode ntpq rl command ! */
294 wsprintf(pp
->a_lastcode
,
295 "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d",
305 pp
->lencode
= strlen(pp
->a_lastcode
);
306 if ((synch
&& 0xc) == 0 ){ /* time ok? */
307 refclock_report(peer
, CEVNT_BADTIME
);
308 pp
->leap
= LEAP_NOTINSYNC
;
313 * If clock has no valid status then report error and exit
315 if ((synch
& HOPF_OPMODE
) == HOPF_INVALID
){ /* time ok? */
316 refclock_report(peer
, CEVNT_BADTIME
);
317 pp
->leap
= LEAP_NOTINSYNC
;
322 * Test if time is running on internal quarz
323 * if CLK_FLAG1 is set, sychronize even if no radio operation
326 if ((synch
& HOPF_OPMODE
) == HOPF_INTERNAL
){
327 if ((pp
->sloppyclockflag
& CLK_FLAG1
) == 0) {
328 refclock_report(peer
, CEVNT_BADTIME
);
329 pp
->leap
= LEAP_NOTINSYNC
;
335 if (!refclock_process(pp
)) {
336 refclock_report(peer
, CEVNT_BADTIME
);
339 pp
->lastref
= pp
->lastrec
;
340 refclock_receive(peer
);
343 msyslog(LOG_ERR
, " D:%x D:%d D:%d",synch
,pp
->minute
,pp
->second
);
346 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
353 * hopfserial_poll - called by the transmit procedure
362 register struct hopfclock_unit
*up
;
363 struct refclockproc
*pp
;
366 up
= (struct hopfclock_unit
*)pp
->unitptr
;
372 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
379 int refclock_hopfser_bs
;
380 #endif /* REFCLOCK */