xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_hopfser.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: refclock_hopfser.c,v 1.1.1.1 2009/12/13 16:55:48 kardel Exp $	*/
2 
3 /*
4  *
5  * refclock_hopfser.c
6  * - clock driver for hopf serial boards (GPS or DCF77)
7  *
8  * Date: 30.03.2000 Revision: 01.10
9  *
10  * latest source and further information can be found at:
11  * http://www.ATLSoft.de/ntp
12  *
13  */
14 
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18 
19 #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
20 
21 #include "ntpd.h"
22 #include "ntp_io.h"
23 #include "ntp_control.h"
24 #include "ntp_refclock.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_stdlib.h"
27 
28 #if defined HAVE_SYS_MODEM_H
29 # include <sys/modem.h>
30 # ifndef __QNXNTO__
31 #  define TIOCMSET MCSETA
32 #  define TIOCMGET MCGETA
33 #  define TIOCM_RTS MRTS
34 # endif
35 #endif
36 
37 #ifdef HAVE_TERMIOS_H
38 # ifdef TERMIOS_NEEDS__SVID3
39 #  define _SVID3
40 # endif
41 # include <termios.h>
42 # ifdef TERMIOS_NEEDS__SVID3
43 #  undef _SVID3
44 # endif
45 #endif
46 
47 #ifdef HAVE_SYS_IOCTL_H
48 # include <sys/ioctl.h>
49 #endif
50 
51 #ifdef SYS_WINNT
52 extern int async_write(int, const void *, unsigned int);
53 #undef write
54 #define write(fd, data, octets)	async_write(fd, data, octets)
55 #endif
56 
57 /*
58  * clock definitions
59  */
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 */
63 /*
64  * I/O definitions
65  */
66 #define	DEVICE		"/dev/hopfclock%d" 	/* device name and unit */
67 #define	SPEED232	B9600		    	/* uart speed (9600 baud) */
68 
69 
70 #define STX 0x02
71 #define ETX 0x03
72 #define CR  0x0c
73 #define LF  0x0a
74 
75 /* parse states */
76 #define REC_QUEUE_EMPTY       0
77 #define REC_QUEUE_FULL        1
78 
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 */
84 
85 /*
86  * hopfclock unit control structure.
87  */
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 */
93 	int	rpt_next;
94 };
95 
96 /*
97  * Function prototypes
98  */
99 
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 *); */
105 /*
106  * Transfer vector
107  */
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 */
116 };
117 
118 /*
119  * hopfserial_start - open the devices and initialize data for processing
120  */
121 static int
122 hopfserial_start (
123 	int unit,
124 	struct peer *peer
125 	)
126 {
127 	register struct hopfclock_unit *up;
128 	struct refclockproc *pp;
129 	int fd;
130 	char gpsdev[20];
131 
132 	(void) sprintf(gpsdev, DEVICE, unit);
133 
134 	/* LDISC_STD, LDISC_RAW
135 	 * Open serial port. Use CLK line discipline, if available.
136 	 */
137 	fd = refclock_open(gpsdev, SPEED232, LDISC_CLK);
138 	if (fd <= 0) {
139 #ifdef DEBUG
140 		printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev);
141 #endif
142 		return 0;
143 	}
144 
145 	msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd,
146 		gpsdev);
147 
148 	/*
149 	 * Allocate and initialize unit structure
150 	 */
151 	up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
152 
153 	if (!(up)) {
154                 msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit);
155 #ifdef DEBUG
156                 printf("hopfSerialClock(%d) emalloc\n",unit);
157 #endif
158 		(void) close(fd);
159 		return (0);
160 	}
161 
162 	memset((char *)up, 0, sizeof(struct hopfclock_unit));
163 	pp = peer->procptr;
164 	pp->unitptr = (caddr_t)up;
165 	pp->io.clock_recv = hopfserial_receive;
166 	pp->io.srcclock = (caddr_t)peer;
167 	pp->io.datalen = 0;
168 	pp->io.fd = fd;
169 	if (!io_addclock(&pp->io)) {
170 #ifdef DEBUG
171                 printf("hopfSerialClock(%d) io_addclock\n",unit);
172 #endif
173 		(void) close(fd);
174 		free(up);
175 		return (0);
176 	}
177 
178 	/*
179 	 * Initialize miscellaneous variables
180 	 */
181 	pp->clockdesc = DESCRIPTION;
182 	peer->precision = PRECISION;
183 	peer->burst = NSTAGE;
184 	memcpy((char *)&pp->refid, REFID, 4);
185 
186 	up->leap_status = 0;
187 	up->unit = (short) unit;
188 
189 	return (1);
190 }
191 
192 
193 /*
194  * hopfserial_shutdown - shut down the clock
195  */
196 static void
197 hopfserial_shutdown (
198 	int unit,
199 	struct peer *peer
200 	)
201 {
202 	register struct hopfclock_unit *up;
203 	struct refclockproc *pp;
204 
205 	pp = peer->procptr;
206 	up = (struct hopfclock_unit *)pp->unitptr;
207 	io_closeclock(&pp->io);
208 	free(up);
209 }
210 
211 
212 
213 /*
214  * hopfserial_receive - receive data from the serial interface
215  */
216 
217 static void
218 hopfserial_receive (
219 	struct recvbuf *rbufp
220 	)
221 {
222 	struct hopfclock_unit *up;
223 	struct refclockproc *pp;
224 	struct peer *peer;
225 
226 	int		synch;	/* synchhronization indicator */
227 	int		DoW;	/* Dow */
228 
229 	int	day, month;	/* ddd conversion */
230 
231 	/*
232 	 * Initialize pointers and read the timecode and timestamp.
233 	 */
234 	peer = (struct peer *)rbufp->recv_srcclock;
235 	pp = peer->procptr;
236 	up = (struct hopfclock_unit *)pp->unitptr;
237 
238 	if (up->rpt_next == 0 )
239 		return;
240 
241 
242 	up->rpt_next = 0; /* wait until next poll interval occur */
243 
244 	pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
245 
246 	if (pp->lencode  == 0)
247 		return;
248 
249 	sscanf(pp->a_lastcode,
250 #if 1
251 	       "%1x%1x%2d%2d%2d%2d%2d%2d",   /* ...cr,lf */
252 #else
253 	       "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
254 #endif
255 	       &synch,
256 	       &DoW,
257 	       &pp->hour,
258 	       &pp->minute,
259 	       &pp->second,
260 	       &day,
261 	       &month,
262 	       &pp->year);
263 
264 
265 	/*
266 	  Validate received values at least enough to prevent internal
267 	  array-bounds problems, etc.
268 	*/
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);
277 		return;
278 	}
279 	/*
280 	  some preparations
281 	*/
282 	pp->day    = ymd2yd(pp->year,month,day);
283 	pp->leap=0;
284 
285 	/* Year-2000 check! */
286 	/* wrap 2-digit date into 4-digit */
287 
288 	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* < 98 */
289 	pp->year += 1900;
290 
291 	/* preparation for timecode ntpq rl command ! */
292 
293 #if 0
294 	wsprintf(pp->a_lastcode,
295 		 "STATUS: %1X%1X, DATE: %02d.%02d.%04d  TIME: %02d:%02d:%02d",
296 		 synch,
297 		 DoW,
298 		 day,
299 		 month,
300 		 pp->year,
301 		 pp->hour,
302 		 pp->minute,
303 		 pp->second);
304 
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;
309 		return;
310 	}
311 #endif
312 	/*
313 	 * If clock has no valid status then report error and exit
314 	 */
315 	if ((synch & HOPF_OPMODE) == HOPF_INVALID ){  /* time ok? */
316 		refclock_report(peer, CEVNT_BADTIME);
317 		pp->leap = LEAP_NOTINSYNC;
318 		return;
319 	}
320 
321 	/*
322 	 * Test if time is running on internal quarz
323 	 * if CLK_FLAG1 is set, sychronize even if no radio operation
324 	 */
325 
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;
330 			return;
331 		}
332 	}
333 
334 
335 	if (!refclock_process(pp)) {
336 		refclock_report(peer, CEVNT_BADTIME);
337 		return;
338 	}
339 	pp->lastref = pp->lastrec;
340 	refclock_receive(peer);
341 
342 #if 0
343 	msyslog(LOG_ERR, " D:%x  D:%d D:%d",synch,pp->minute,pp->second);
344 #endif
345 
346 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
347 
348 	return;
349 }
350 
351 
352 /*
353  * hopfserial_poll - called by the transmit procedure
354  *
355  */
356 static void
357 hopfserial_poll (
358 	int unit,
359 	struct peer *peer
360 	)
361 {
362 	register struct hopfclock_unit *up;
363 	struct refclockproc *pp;
364 	pp = peer->procptr;
365 
366 	up = (struct hopfclock_unit *)pp->unitptr;
367 
368 	pp->polls++;
369 	up->rpt_next = 1;
370 
371 #if 0
372 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
373 #endif
374 
375 	return;
376 }
377 
378 #else
379 int refclock_hopfser_bs;
380 #endif /* REFCLOCK */
381