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