]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpd/refclock_hopfser.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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        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 *)); */
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 #ifdef SYS_WINNT
131         (void) sprintf(gpsdev, "COM%d:", unit);
132 #else
133         (void) sprintf(gpsdev, DEVICE, unit);
134 #endif
135         /* LDISC_STD, LDISC_RAW
136          * Open serial port. Use CLK line discipline, if available.
137          */
138         fd = refclock_open(gpsdev, SPEED232, LDISC_CLK);
139         if (fd <= 0) {
140 #ifdef DEBUG
141                 printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev);
142 #endif
143                 return 0;
144         }
145
146         msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd,
147                 gpsdev);
148
149         /*
150          * Allocate and initialize unit structure
151          */
152         up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
153
154         if (!(up)) {
155                 msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit);
156 #ifdef DEBUG
157                 printf("hopfSerialClock(%d) emalloc\n",unit);
158 #endif
159                 (void) close(fd);
160                 return (0);
161         }
162
163         memset((char *)up, 0, sizeof(struct hopfclock_unit));
164         pp = peer->procptr;
165         pp->unitptr = (caddr_t)up;
166         pp->io.clock_recv = hopfserial_receive;
167         pp->io.srcclock = (caddr_t)peer;
168         pp->io.datalen = 0;
169         pp->io.fd = fd;
170         if (!io_addclock(&pp->io)) {
171 #ifdef DEBUG
172                 printf("hopfSerialClock(%d) io_addclock\n",unit);
173 #endif
174                 (void) close(fd);
175                 free(up);
176                 return (0);
177         }
178
179         /*
180          * Initialize miscellaneous variables
181          */
182         pp->clockdesc = DESCRIPTION;
183         peer->precision = PRECISION;
184         peer->burst = NSTAGE;
185         memcpy((char *)&pp->refid, REFID, 4);
186
187         up->leap_status = 0;
188         up->unit = (short) unit;
189
190         return (1);
191 }
192
193
194 /*
195  * hopfserial_shutdown - shut down the clock
196  */
197 static void
198 hopfserial_shutdown (
199         int unit,
200         struct peer *peer
201         )
202 {
203         register struct hopfclock_unit *up;
204         struct refclockproc *pp;
205
206         pp = peer->procptr;
207         up = (struct hopfclock_unit *)pp->unitptr;
208         io_closeclock(&pp->io);
209         free(up);
210 }
211
212
213
214 /*
215  * hopfserial_receive - receive data from the serial interface
216  */
217
218 static void
219 hopfserial_receive (
220         struct recvbuf *rbufp
221         )
222 {
223         struct hopfclock_unit *up;
224         struct refclockproc *pp;
225         struct peer *peer;
226
227         int             synch;  /* synchhronization indicator */
228         int             DoW;    /* Dow */
229
230         int     day, month;     /* ddd conversion */
231
232         /*
233          * Initialize pointers and read the timecode and timestamp.
234          */
235         peer = (struct peer *)rbufp->recv_srcclock;
236         pp = peer->procptr;
237         up = (struct hopfclock_unit *)pp->unitptr;
238
239         if (up->rpt_next == 0 )
240                 return;
241
242
243         up->rpt_next = 0; /* wait until next poll interval occur */
244
245         pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
246
247         if (pp->lencode  == 0)
248                 return;
249
250         sscanf(pp->a_lastcode,
251 #if 1
252                "%1x%1x%2d%2d%2d%2d%2d%2d",   /* ...cr,lf */
253 #else
254                "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
255 #endif
256                &synch,
257                &DoW,
258                &pp->hour,
259                &pp->minute,
260                &pp->second,
261                &day,
262                &month,
263                &pp->year);
264
265
266         /*
267           Validate received values at least enough to prevent internal
268           array-bounds problems, etc.
269         */
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);
278                 return;
279         }
280         /*
281           some preparations
282         */
283         pp->day    = ymd2yd(pp->year,month,day);
284         pp->leap=0;
285
286         /* Year-2000 check! */
287         /* wrap 2-digit date into 4-digit */
288
289         if(pp->year < YEAR_PIVOT) { pp->year += 100; }          /* < 98 */
290         pp->year += 1900;
291
292         /* preparation for timecode ntpq rl command ! */
293
294 #if 0
295         wsprintf(pp->a_lastcode,
296                  "STATUS: %1X%1X, DATE: %02d.%02d.%04d  TIME: %02d:%02d:%02d",
297                  synch,
298                  DoW,
299                  day,
300                  month,
301                  pp->year,
302                  pp->hour,
303                  pp->minute,
304                  pp->second);
305
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;
310                 return;
311         }
312 #endif
313         /*
314          * If clock has no valid status then report error and exit
315          */
316         if ((synch & HOPF_OPMODE) == HOPF_INVALID ){  /* time ok? */
317                 refclock_report(peer, CEVNT_BADTIME);
318                 pp->leap = LEAP_NOTINSYNC;
319                 return;
320         }
321
322         /*
323          * Test if time is running on internal quarz
324          * if CLK_FLAG1 is set, sychronize even if no radio operation
325          */
326
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;
331                         return;
332                 }
333         }
334
335
336         if (!refclock_process(pp)) {
337                 refclock_report(peer, CEVNT_BADTIME);
338                 return;
339         }
340         pp->lastref = pp->lastrec;
341         refclock_receive(peer);
342
343 #if 0
344         msyslog(LOG_ERR, " D:%x  D:%d D:%d",synch,pp->minute,pp->second);
345 #endif
346
347         record_clock_stats(&peer->srcadr, pp->a_lastcode);
348
349         return;
350 }
351
352
353 /*
354  * hopfserial_poll - called by the transmit procedure
355  *
356  */
357 static void
358 hopfserial_poll (
359         int unit,
360         struct peer *peer
361         )
362 {
363         register struct hopfclock_unit *up;
364         struct refclockproc *pp;
365         pp = peer->procptr;
366
367         up = (struct hopfclock_unit *)pp->unitptr;
368
369         pp->polls++;
370         up->rpt_next = 1;
371
372 #if 0
373         record_clock_stats(&peer->srcadr, pp->a_lastcode);
374 #endif
375
376         return;
377 }
378
379 #else
380 int refclock_hopfser_bs;
381 #endif /* REFCLOCK */