]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/ntp/ntpd/refclock_hopfser.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / ntp / ntpd / refclock_hopfser.c
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 # ifndef __QNXNTO__
34 #  define TIOCMSET MCSETA
35 #  define TIOCMGET MCGETA
36 #  define TIOCM_RTS MRTS
37 # endif
38 #endif
39
40 #ifdef HAVE_TERMIOS_H
41 # ifdef TERMIOS_NEEDS__SVID3
42 #  define _SVID3
43 # endif
44 # include <termios.h>
45 # ifdef TERMIOS_NEEDS__SVID3
46 #  undef _SVID3
47 # endif
48 #endif
49
50 #ifdef HAVE_SYS_IOCTL_H
51 # include <sys/ioctl.h>
52 #endif
53
54 /*
55  * clock definitions
56  */
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 */
60 /*
61  * I/O definitions
62  */
63 #define DEVICE          "/dev/hopfclock%d"      /* device name and unit */
64 #define SPEED232        B9600                   /* uart speed (9600 baud) */
65
66
67 #define STX 0x02
68 #define ETX 0x03
69 #define CR  0x0c
70 #define LF  0x0a
71
72 /* parse states */
73 #define REC_QUEUE_EMPTY       0
74 #define REC_QUEUE_FULL        1
75
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 */
81
82 /*
83  * hopfclock unit control structure.
84  */
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 */
90         int     rpt_next;
91 };
92
93 /*
94  * Function prototypes
95  */
96
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 *)); */
102 /*
103  * Transfer vector
104  */
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 */
113 };
114
115 /*
116  * hopfserial_start - open the devices and initialize data for processing
117  */
118 static int
119 hopfserial_start (
120         int unit,
121         struct peer *peer
122         )
123 {
124         register struct hopfclock_unit *up;
125         struct refclockproc *pp;
126         int fd;
127         char gpsdev[20];
128
129 #ifdef SYS_WINNT
130         (void) sprintf(gpsdev, "COM%d:", unit);
131 #else
132         (void) sprintf(gpsdev, DEVICE, unit);
133 #endif
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 */