4 * - clock driver for hopf serial boards (GPS or DCF77)
6 * Date: 30.03.2000 Revision: 01.10
8 * latest source and further information can be found at:
9 * http://www.ATLSoft.de/ntp
17 #if defined(SYS_WINNT)
19 #define close closesocket
22 #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
26 #include "ntp_control.h"
27 #include "ntp_refclock.h"
28 #include "ntp_unixtime.h"
29 #include "ntp_stdlib.h"
31 #if defined HAVE_SYS_MODEM_H
32 # include <sys/modem.h>
34 # define TIOCMSET MCSETA
35 # define TIOCMGET MCGETA
36 # define TIOCM_RTS MRTS
41 # ifdef TERMIOS_NEEDS__SVID3
45 # ifdef TERMIOS_NEEDS__SVID3
50 #ifdef HAVE_SYS_IOCTL_H
51 # include <sys/ioctl.h>
57 #define DESCRIPTION "hopf Elektronik serial clock" /* Long name */
58 #define PRECISION (-10) /* precision assumed (about 1 ms) */
59 #define REFID "hopf\0" /* reference ID */
63 #define DEVICE "/dev/hopfclock%d" /* device name and unit */
64 #define SPEED232 B9600 /* uart speed (9600 baud) */
73 #define REC_QUEUE_EMPTY 0
74 #define REC_QUEUE_FULL 1
76 #define HOPF_OPMODE 0x0C /* operation mode mask */
77 #define HOPF_INVALID 0x00 /* no time code available */
78 #define HOPF_INTERNAL 0x04 /* internal clock */
79 #define HOPF_RADIO 0x08 /* radio clock */
80 #define HOPF_RADIOHP 0x0C /* high precision radio clock */
83 * hopfclock unit control structure.
85 struct hopfclock_unit
{
86 l_fp laststamp
; /* last receive timestamp */
87 short unit
; /* NTP refclock unit number */
88 u_long polled
; /* flag to detect noreplies */
89 char leap_status
; /* leap second flag */
97 static int hopfserial_start
P((int, struct peer
*));
98 static void hopfserial_shutdown
P((int, struct peer
*));
99 static void hopfserial_receive
P((struct recvbuf
*));
100 static void hopfserial_poll
P((int, struct peer
*));
101 /* static void hopfserial_io P((struct recvbuf *)); */
105 struct refclock refclock_hopfser
= {
106 hopfserial_start
, /* start up driver */
107 hopfserial_shutdown
, /* shut down driver */
108 hopfserial_poll
, /* transmit poll message */
109 noentry
, /* not used */
110 noentry
, /* initialize driver (not used) */
111 noentry
, /* not used */
112 NOFLAGS
/* not used */
116 * hopfserial_start - open the devices and initialize data for processing
124 register struct hopfclock_unit
*up
;
125 struct refclockproc
*pp
;
130 (void) sprintf(gpsdev
, "COM%d:", unit
);
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 */