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