1 /* $NetBSD: refclock_hopfser.c,v 1.3 2006/06/11 19:34:12 kardel Exp $ */
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
P((int, struct peer
*));
101 static void hopfserial_shutdown
P((int, struct peer
*));
102 static void hopfserial_receive
P((struct recvbuf
*));
103 static void hopfserial_poll
P((int, struct peer
*));
104 /* static void hopfserial_io P((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
;
133 (void) sprintf(gpsdev
, "COM%d:", unit
);
135 (void) sprintf(gpsdev
, DEVICE
, unit
);
137 /* LDISC_STD, LDISC_RAW
138 * Open serial port. Use CLK line discipline, if available.
140 fd
= refclock_open(gpsdev
, SPEED232
, LDISC_CLK
);
143 printf("hopfSerialClock(%d) start: open %s failed\n", unit
, gpsdev
);
148 msyslog(LOG_NOTICE
, "hopfSerialClock(%d) fd: %d dev: %s", unit
, fd
,
152 * Allocate and initialize unit structure
154 up
= (struct hopfclock_unit
*) emalloc(sizeof(struct hopfclock_unit
));
157 msyslog(LOG_ERR
, "hopfSerialClock(%d) emalloc: %m",unit
);
159 printf("hopfSerialClock(%d) emalloc\n",unit
);
165 memset((char *)up
, 0, sizeof(struct hopfclock_unit
));
167 pp
->unitptr
= (caddr_t
)up
;
168 pp
->io
.clock_recv
= hopfserial_receive
;
169 pp
->io
.srcclock
= (caddr_t
)peer
;
172 if (!io_addclock(&pp
->io
)) {
174 printf("hopfSerialClock(%d) io_addclock\n",unit
);
182 * Initialize miscellaneous variables
184 pp
->clockdesc
= DESCRIPTION
;
185 peer
->precision
= PRECISION
;
186 peer
->burst
= NSTAGE
;
187 memcpy((char *)&pp
->refid
, REFID
, 4);
190 up
->unit
= (short) unit
;
197 * hopfserial_shutdown - shut down the clock
200 hopfserial_shutdown (
205 register struct hopfclock_unit
*up
;
206 struct refclockproc
*pp
;
209 up
= (struct hopfclock_unit
*)pp
->unitptr
;
210 io_closeclock(&pp
->io
);
217 * hopfserial_receive - receive data from the serial interface
222 struct recvbuf
*rbufp
225 struct hopfclock_unit
*up
;
226 struct refclockproc
*pp
;
229 int synch
; /* synchhronization indicator */
232 int day
, month
; /* ddd conversion */
235 * Initialize pointers and read the timecode and timestamp.
237 peer
= (struct peer
*)rbufp
->recv_srcclock
;
239 up
= (struct hopfclock_unit
*)pp
->unitptr
;
241 if (up
->rpt_next
== 0 )
245 up
->rpt_next
= 0; /* wait until next poll interval occur */
247 pp
->lencode
= (u_short
)refclock_gtlin(rbufp
, pp
->a_lastcode
, BMAX
, &pp
->lastrec
);
249 if (pp
->lencode
== 0)
252 sscanf(pp
->a_lastcode
,
254 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */
256 "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
269 Validate received values at least enough to prevent internal
270 array-bounds problems, etc.
272 if((pp
->hour
< 0) || (pp
->hour
> 23) ||
273 (pp
->minute
< 0) || (pp
->minute
> 59) ||
274 (pp
->second
< 0) || (pp
->second
> 60) /*Allow for leap seconds.*/ ||
275 (day
< 1) || (day
> 31) ||
276 (month
< 1) || (month
> 12) ||
277 (pp
->year
< 0) || (pp
->year
> 99)) {
278 /* Data out of range. */
279 refclock_report(peer
, CEVNT_BADREPLY
);
285 pp
->day
= ymd2yd(pp
->year
,month
,day
);
288 /* Year-2000 check! */
289 /* wrap 2-digit date into 4-digit */
291 if(pp
->year
< YEAR_PIVOT
) { pp
->year
+= 100; } /* < 98 */
294 /* preparation for timecode ntpq rl command ! */
297 wsprintf(pp
->a_lastcode
,
298 "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d",
308 pp
->lencode
= strlen(pp
->a_lastcode
);
309 if ((synch
&& 0xc) == 0 ){ /* time ok? */
310 refclock_report(peer
, CEVNT_BADTIME
);
311 pp
->leap
= LEAP_NOTINSYNC
;
316 * If clock has no valid status then report error and exit
318 if ((synch
& HOPF_OPMODE
) == HOPF_INVALID
){ /* time ok? */
319 refclock_report(peer
, CEVNT_BADTIME
);
320 pp
->leap
= LEAP_NOTINSYNC
;
325 * Test if time is running on internal quarz
326 * if CLK_FLAG1 is set, sychronize even if no radio operation
329 if ((synch
& HOPF_OPMODE
) == HOPF_INTERNAL
){
330 if ((pp
->sloppyclockflag
& CLK_FLAG1
) == 0) {
331 refclock_report(peer
, CEVNT_BADTIME
);
332 pp
->leap
= LEAP_NOTINSYNC
;
338 if (!refclock_process(pp
)) {
339 refclock_report(peer
, CEVNT_BADTIME
);
342 pp
->lastref
= pp
->lastrec
;
343 refclock_receive(peer
);
346 msyslog(LOG_ERR
, " D:%x D:%d D:%d",synch
,pp
->minute
,pp
->second
);
349 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
356 * hopfserial_poll - called by the transmit procedure
365 register struct hopfclock_unit
*up
;
366 struct refclockproc
*pp
;
369 up
= (struct hopfclock_unit
*)pp
->unitptr
;
375 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
382 int refclock_hopfser_bs
;
383 #endif /* REFCLOCK */