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