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(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
21 #include "ntp_control.h"
22 #include "ntp_refclock.h"
23 #include "ntp_unixtime.h"
24 #include "ntp_stdlib.h"
26 #if defined HAVE_SYS_MODEM_H
27 # include <sys/modem.h>
29 # define TIOCMSET MCSETA
30 # define TIOCMGET MCGETA
31 # define TIOCM_RTS MRTS
36 # ifdef TERMIOS_NEEDS__SVID3
40 # ifdef TERMIOS_NEEDS__SVID3
45 #ifdef HAVE_SYS_IOCTL_H
46 # include <sys/ioctl.h>
50 extern int async_write(int, const void *, unsigned int);
52 #define write(fd, data, octets) async_write(fd, data, octets)
58 #define DESCRIPTION "hopf Elektronik serial clock" /* Long name */
59 #define PRECISION (-10) /* precision assumed (about 1 ms) */
60 #define REFID "hopf\0" /* reference ID */
64 #define DEVICE "/dev/hopfclock%d" /* device name and unit */
65 #define SPEED232 B9600 /* uart speed (9600 baud) */
74 #define REC_QUEUE_EMPTY 0
75 #define REC_QUEUE_FULL 1
77 #define HOPF_OPMODE 0x0C /* operation mode mask */
78 #define HOPF_INVALID 0x00 /* no time code available */
79 #define HOPF_INTERNAL 0x04 /* internal clock */
80 #define HOPF_RADIO 0x08 /* radio clock */
81 #define HOPF_RADIOHP 0x0C /* high precision radio clock */
84 * hopfclock unit control structure.
86 struct hopfclock_unit {
87 l_fp laststamp; /* last receive timestamp */
88 short unit; /* NTP refclock unit number */
89 u_long polled; /* flag to detect noreplies */
90 char leap_status; /* leap second flag */
98 static int hopfserial_start P((int, struct peer *));
99 static void hopfserial_shutdown P((int, struct peer *));
100 static void hopfserial_receive P((struct recvbuf *));
101 static void hopfserial_poll P((int, struct peer *));
102 /* static void hopfserial_io P((struct recvbuf *)); */
106 struct refclock refclock_hopfser = {
107 hopfserial_start, /* start up driver */
108 hopfserial_shutdown, /* shut down driver */
109 hopfserial_poll, /* transmit poll message */
110 noentry, /* not used */
111 noentry, /* initialize driver (not used) */
112 noentry, /* not used */
113 NOFLAGS /* not used */
117 * hopfserial_start - open the devices and initialize data for processing
125 register struct hopfclock_unit *up;
126 struct refclockproc *pp;
131 (void) sprintf(gpsdev, "COM%d:", unit);
133 (void) sprintf(gpsdev, DEVICE, unit);
135 /* LDISC_STD, LDISC_RAW
136 * Open serial port. Use CLK line discipline, if available.
138 fd = refclock_open(gpsdev, SPEED232, LDISC_CLK);
141 printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev);
146 msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd,
150 * Allocate and initialize unit structure
152 up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
155 msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit);
157 printf("hopfSerialClock(%d) emalloc\n",unit);
163 memset((char *)up, 0, sizeof(struct hopfclock_unit));
165 pp->unitptr = (caddr_t)up;
166 pp->io.clock_recv = hopfserial_receive;
167 pp->io.srcclock = (caddr_t)peer;
170 if (!io_addclock(&pp->io)) {
172 printf("hopfSerialClock(%d) io_addclock\n",unit);
180 * Initialize miscellaneous variables
182 pp->clockdesc = DESCRIPTION;
183 peer->precision = PRECISION;
184 peer->burst = NSTAGE;
185 memcpy((char *)&pp->refid, REFID, 4);
188 up->unit = (short) unit;
195 * hopfserial_shutdown - shut down the clock
198 hopfserial_shutdown (
203 register struct hopfclock_unit *up;
204 struct refclockproc *pp;
207 up = (struct hopfclock_unit *)pp->unitptr;
208 io_closeclock(&pp->io);
215 * hopfserial_receive - receive data from the serial interface
220 struct recvbuf *rbufp
223 struct hopfclock_unit *up;
224 struct refclockproc *pp;
227 int synch; /* synchhronization indicator */
230 int day, month; /* ddd conversion */
233 * Initialize pointers and read the timecode and timestamp.
235 peer = (struct peer *)rbufp->recv_srcclock;
237 up = (struct hopfclock_unit *)pp->unitptr;
239 if (up->rpt_next == 0 )
243 up->rpt_next = 0; /* wait until next poll interval occur */
245 pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
247 if (pp->lencode == 0)
250 sscanf(pp->a_lastcode,
252 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */
254 "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
267 Validate received values at least enough to prevent internal
268 array-bounds problems, etc.
270 if((pp->hour < 0) || (pp->hour > 23) ||
271 (pp->minute < 0) || (pp->minute > 59) ||
272 (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
273 (day < 1) || (day > 31) ||
274 (month < 1) || (month > 12) ||
275 (pp->year < 0) || (pp->year > 99)) {
276 /* Data out of range. */
277 refclock_report(peer, CEVNT_BADREPLY);
283 pp->day = ymd2yd(pp->year,month,day);
286 /* Year-2000 check! */
287 /* wrap 2-digit date into 4-digit */
289 if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */
292 /* preparation for timecode ntpq rl command ! */
295 wsprintf(pp->a_lastcode,
296 "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d",
306 pp->lencode = strlen(pp->a_lastcode);
307 if ((synch && 0xc) == 0 ){ /* time ok? */
308 refclock_report(peer, CEVNT_BADTIME);
309 pp->leap = LEAP_NOTINSYNC;
314 * If clock has no valid status then report error and exit
316 if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */
317 refclock_report(peer, CEVNT_BADTIME);
318 pp->leap = LEAP_NOTINSYNC;
323 * Test if time is running on internal quarz
324 * if CLK_FLAG1 is set, sychronize even if no radio operation
327 if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){
328 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
329 refclock_report(peer, CEVNT_BADTIME);
330 pp->leap = LEAP_NOTINSYNC;
336 if (!refclock_process(pp)) {
337 refclock_report(peer, CEVNT_BADTIME);
340 pp->lastref = pp->lastrec;
341 refclock_receive(peer);
344 msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second);
347 record_clock_stats(&peer->srcadr, pp->a_lastcode);
354 * hopfserial_poll - called by the transmit procedure
363 register struct hopfclock_unit *up;
364 struct refclockproc *pp;
367 up = (struct hopfclock_unit *)pp->unitptr;
373 record_clock_stats(&peer->srcadr, pp->a_lastcode);
380 int refclock_hopfser_bs;
381 #endif /* REFCLOCK */