]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/ntpd/refclock_hopfser.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
18
19 #include "ntpd.h"
20 #include "ntp_io.h"
21 #include "ntp_control.h"
22 #include "ntp_refclock.h"
23 #include "ntp_unixtime.h"
24 #include "ntp_stdlib.h"
25
26 #if defined HAVE_SYS_MODEM_H
27 # include <sys/modem.h>
28 # ifndef __QNXNTO__
29 #  define TIOCMSET MCSETA
30 #  define TIOCMGET MCGETA
31 #  define TIOCM_RTS MRTS
32 # endif
33 #endif
34
35 #ifdef HAVE_TERMIOS_H
36 # ifdef TERMIOS_NEEDS__SVID3
37 #  define _SVID3
38 # endif
39 # include <termios.h>
40 # ifdef TERMIOS_NEEDS__SVID3
41 #  undef _SVID3
42 # endif
43 #endif
44
45 #ifdef HAVE_SYS_IOCTL_H
46 # include <sys/ioctl.h>
47 #endif
48
49 #ifdef SYS_WINNT
50 extern int async_write(int, const void *, unsigned int);
51 #undef write
52 #define write(fd, data, octets) async_write(fd, data, octets)
53 #endif
54
55 /*
56  * clock definitions
57  */
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 */
61 /*
62  * I/O definitions
63  */
64 #define DEVICE          "/dev/hopfclock%d"      /* device name and unit */
65 #define SPEED232        B9600                   /* uart speed (9600 baud) */
66
67
68 #define STX 0x02
69 #define ETX 0x03
70 #define CR  0x0c
71 #define LF  0x0a
72
73 /* parse states */
74 #define REC_QUEUE_EMPTY       0
75 #define REC_QUEUE_FULL        1
76
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 */
82
83 /*
84  * hopfclock unit control structure.
85  */
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 */
91         int     rpt_next;
92 };
93
94 /*
95  * Function prototypes
96  */
97
98 static  int     hopfserial_start        (int, struct peer *);
99 static  void    hopfserial_shutdown     (int, struct peer *);
100 static  void    hopfserial_receive      (struct recvbuf *);
101 static  void    hopfserial_poll         (int, struct peer *);
102 /* static  void hopfserial_io           (struct recvbuf *); */
103 /*
104  * Transfer vector
105  */
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 */
114 };
115
116 /*
117  * hopfserial_start - open the devices and initialize data for processing
118  */
119 static int
120 hopfserial_start (
121         int unit,
122         struct peer *peer
123         )
124 {
125         register struct hopfclock_unit *up;
126         struct refclockproc *pp;
127         int fd;
128         char gpsdev[20];
129
130         snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
131
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 = emalloc_zero(sizeof(*up));
150         pp = peer->procptr;
151         pp->unitptr = up;
152         pp->io.clock_recv = hopfserial_receive;
153         pp->io.srcclock = peer;
154         pp->io.datalen = 0;
155         pp->io.fd = fd;
156         if (!io_addclock(&pp->io)) {
157 #ifdef DEBUG
158                 printf("hopfSerialClock(%d) io_addclock\n", unit);
159 #endif
160                 close(fd);
161                 pp->io.fd = -1;
162                 free(up);
163                 pp->unitptr = NULL;
164                 return (0);
165         }
166
167         /*
168          * Initialize miscellaneous variables
169          */
170         pp->clockdesc = DESCRIPTION;
171         peer->precision = PRECISION;
172         memcpy((char *)&pp->refid, REFID, 4);
173
174         up->leap_status = 0;
175         up->unit = (short) unit;
176
177         return (1);
178 }
179
180
181 /*
182  * hopfserial_shutdown - shut down the clock
183  */
184 static void
185 hopfserial_shutdown (
186         int unit,
187         struct peer *peer
188         )
189 {
190         register struct hopfclock_unit *up;
191         struct refclockproc *pp;
192
193         pp = peer->procptr;
194         up = pp->unitptr;
195
196         if (-1 != pp->io.fd)
197                 io_closeclock(&pp->io);
198         if (NULL != up)
199                 free(up);
200 }
201
202
203
204 /*
205  * hopfserial_receive - receive data from the serial interface
206  */
207
208 static void
209 hopfserial_receive (
210         struct recvbuf *rbufp
211         )
212 {
213         struct hopfclock_unit *up;
214         struct refclockproc *pp;
215         struct peer *peer;
216
217         int     synch;  /* synchhronization indicator */
218         int     DoW;    /* Day of Week */
219
220         int     day, month;     /* ddd conversion */
221         int     converted;
222
223         /*
224          * Initialize pointers and read the timecode and timestamp.
225          */
226         peer = rbufp->recv_peer;
227         pp = peer->procptr;
228         up = pp->unitptr;
229
230         if (up->rpt_next == 0 )
231                 return;
232
233         up->rpt_next = 0; /* wait until next poll interval occur */
234
235         pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode,
236                                               sizeof(pp->a_lastcode),
237                                               &pp->lastrec);
238         if (pp->lencode == 0)
239                 return;
240
241         converted = sscanf(pp->a_lastcode,
242 #if 1
243                "%1x%1x%2d%2d%2d%2d%2d%2d",   /* ...cr,lf */
244 #else
245                "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
246 #endif
247                &synch,
248                &DoW,
249                &pp->hour,
250                &pp->minute,
251                &pp->second,
252                &day,
253                &month,
254                &pp->year);
255
256
257         /*
258           Validate received values at least enough to prevent internal
259           array-bounds problems, etc.
260         */
261         if ((8 != converted) || (pp->hour < 0) || (pp->hour > 23) ||
262            (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) ||
263            (pp->second > 60) /*Allow for leap seconds.*/ ||
264            (day < 1) || (day > 31) ||
265            (month < 1) || (month > 12) ||
266            (pp->year < 0) || (pp->year > 99)) {
267                 /* Data out of range. */
268                 refclock_report(peer, CEVNT_BADREPLY);
269                 return;
270         }
271         /*
272           some preparations
273         */
274         pp->day    = ymd2yd(pp->year,month,day);
275         pp->leap=0;
276
277         /* Year-2000 check! */
278         /* wrap 2-digit date into 4-digit */
279
280         if(pp->year < YEAR_PIVOT) { pp->year += 100; }          /* < 98 */
281         pp->year += 1900;
282
283         /* preparation for timecode ntpq rl command ! */
284
285 #if 0
286         snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
287                  "STATUS: %1X%1X, DATE: %02d.%02d.%04d  TIME: %02d:%02d:%02d",
288                  synch,
289                  DoW,
290                  day,
291                  month,
292                  pp->year,
293                  pp->hour,
294                  pp->minute,
295                  pp->second);
296
297         pp->lencode = strlen(pp->a_lastcode);
298         if ((synch && 0xc) == 0 ){  /* time ok? */
299                 refclock_report(peer, CEVNT_BADTIME);
300                 pp->leap = LEAP_NOTINSYNC;
301                 return;
302         }
303 #endif
304         /*
305          * If clock has no valid status then report error and exit
306          */
307         if ((synch & HOPF_OPMODE) == HOPF_INVALID ){  /* time ok? */
308                 refclock_report(peer, CEVNT_BADTIME);
309                 pp->leap = LEAP_NOTINSYNC;
310                 return;
311         }
312
313         /*
314          * Test if time is running on internal quarz
315          * if CLK_FLAG1 is set, sychronize even if no radio operation
316          */
317
318         if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){
319                 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
320                         refclock_report(peer, CEVNT_BADTIME);
321                         pp->leap = LEAP_NOTINSYNC;
322                         return;
323                 }
324         }
325
326
327         if (!refclock_process(pp)) {
328                 refclock_report(peer, CEVNT_BADTIME);
329                 return;
330         }
331         pp->lastref = pp->lastrec;
332         refclock_receive(peer);
333
334 #if 0
335         msyslog(LOG_ERR, " D:%x  D:%d D:%d",synch,pp->minute,pp->second);
336 #endif
337
338         record_clock_stats(&peer->srcadr, pp->a_lastcode);
339
340         return;
341 }
342
343
344 /*
345  * hopfserial_poll - called by the transmit procedure
346  *
347  */
348 static void
349 hopfserial_poll (
350         int unit,
351         struct peer *peer
352         )
353 {
354         register struct hopfclock_unit *up;
355         struct refclockproc *pp;
356         pp = peer->procptr;
357
358         up = pp->unitptr;
359
360         pp->polls++;
361         up->rpt_next = 1;
362
363 #if 0
364         record_clock_stats(&peer->srcadr, pp->a_lastcode);
365 #endif
366
367         return;
368 }
369
370 #else
371 int refclock_hopfser_bs;
372 #endif /* REFCLOCK */