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
hopfserial_start(int unit,struct peer * peer)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
hopfserial_shutdown(int unit,struct peer * peer)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
hopfserial_receive(struct recvbuf * rbufp)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
hopfserial_poll(int unit,struct peer * peer)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 */
373