Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpd / refclock_hopfser.c
blobcc69aaf233d156ac8279e49ca1b6b9192465b155
1 /* $NetBSD: refclock_hopfser.c,v 1.3 2006/06/11 19:34:12 kardel Exp $ */
3 /*
5 * refclock_hopfser.c
6 * - clock driver for hopf serial boards (GPS or DCF77)
8 * Date: 30.03.2000 Revision: 01.10
10 * latest source and further information can be found at:
11 * http://www.ATLSoft.de/ntp
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
19 #if defined(REFCLOCK) && (defined(CLOCK_HOPF_SERIAL))
21 #include "ntpd.h"
22 #include "ntp_io.h"
23 #include "ntp_control.h"
24 #include "ntp_refclock.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_stdlib.h"
28 #if defined HAVE_SYS_MODEM_H
29 # include <sys/modem.h>
30 # ifndef __QNXNTO__
31 # define TIOCMSET MCSETA
32 # define TIOCMGET MCGETA
33 # define TIOCM_RTS MRTS
34 # endif
35 #endif
37 #ifdef HAVE_TERMIOS_H
38 # ifdef TERMIOS_NEEDS__SVID3
39 # define _SVID3
40 # endif
41 # include <termios.h>
42 # ifdef TERMIOS_NEEDS__SVID3
43 # undef _SVID3
44 # endif
45 #endif
47 #ifdef HAVE_SYS_IOCTL_H
48 # include <sys/ioctl.h>
49 #endif
51 #ifdef SYS_WINNT
52 extern int async_write(int, const void *, unsigned int);
53 #undef write
54 #define write(fd, data, octets) async_write(fd, data, octets)
55 #endif
58 * clock definitions
60 #define DESCRIPTION "hopf Elektronik serial clock" /* Long name */
61 #define PRECISION (-10) /* precision assumed (about 1 ms) */
62 #define REFID "hopf\0" /* reference ID */
64 * I/O definitions
66 #define DEVICE "/dev/hopfclock%d" /* device name and unit */
67 #define SPEED232 B9600 /* uart speed (9600 baud) */
70 #define STX 0x02
71 #define ETX 0x03
72 #define CR 0x0c
73 #define LF 0x0a
75 /* parse states */
76 #define REC_QUEUE_EMPTY 0
77 #define REC_QUEUE_FULL 1
79 #define HOPF_OPMODE 0x0C /* operation mode mask */
80 #define HOPF_INVALID 0x00 /* no time code available */
81 #define HOPF_INTERNAL 0x04 /* internal clock */
82 #define HOPF_RADIO 0x08 /* radio clock */
83 #define HOPF_RADIOHP 0x0C /* high precision radio clock */
86 * hopfclock unit control structure.
88 struct hopfclock_unit {
89 l_fp laststamp; /* last receive timestamp */
90 short unit; /* NTP refclock unit number */
91 u_long polled; /* flag to detect noreplies */
92 char leap_status; /* leap second flag */
93 int rpt_next;
97 * Function prototypes
100 static int hopfserial_start P((int, struct peer *));
101 static void hopfserial_shutdown P((int, struct peer *));
102 static void hopfserial_receive P((struct recvbuf *));
103 static void hopfserial_poll P((int, struct peer *));
104 /* static void hopfserial_io P((struct recvbuf *)); */
106 * Transfer vector
108 struct refclock refclock_hopfser = {
109 hopfserial_start, /* start up driver */
110 hopfserial_shutdown, /* shut down driver */
111 hopfserial_poll, /* transmit poll message */
112 noentry, /* not used */
113 noentry, /* initialize driver (not used) */
114 noentry, /* not used */
115 NOFLAGS /* not used */
119 * hopfserial_start - open the devices and initialize data for processing
121 static int
122 hopfserial_start (
123 int unit,
124 struct peer *peer
127 register struct hopfclock_unit *up;
128 struct refclockproc *pp;
129 int fd;
130 char gpsdev[20];
132 #ifdef SYS_WINNT
133 (void) sprintf(gpsdev, "COM%d:", unit);
134 #else
135 (void) sprintf(gpsdev, DEVICE, unit);
136 #endif
137 /* LDISC_STD, LDISC_RAW
138 * Open serial port. Use CLK line discipline, if available.
140 fd = refclock_open(gpsdev, SPEED232, LDISC_CLK);
141 if (fd <= 0) {
142 #ifdef DEBUG
143 printf("hopfSerialClock(%d) start: open %s failed\n", unit, gpsdev);
144 #endif
145 return 0;
148 msyslog(LOG_NOTICE, "hopfSerialClock(%d) fd: %d dev: %s", unit, fd,
149 gpsdev);
152 * Allocate and initialize unit structure
154 up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
156 if (!(up)) {
157 msyslog(LOG_ERR, "hopfSerialClock(%d) emalloc: %m",unit);
158 #ifdef DEBUG
159 printf("hopfSerialClock(%d) emalloc\n",unit);
160 #endif
161 (void) close(fd);
162 return (0);
165 memset((char *)up, 0, sizeof(struct hopfclock_unit));
166 pp = peer->procptr;
167 pp->unitptr = (caddr_t)up;
168 pp->io.clock_recv = hopfserial_receive;
169 pp->io.srcclock = (caddr_t)peer;
170 pp->io.datalen = 0;
171 pp->io.fd = fd;
172 if (!io_addclock(&pp->io)) {
173 #ifdef DEBUG
174 printf("hopfSerialClock(%d) io_addclock\n",unit);
175 #endif
176 (void) close(fd);
177 free(up);
178 return (0);
182 * Initialize miscellaneous variables
184 pp->clockdesc = DESCRIPTION;
185 peer->precision = PRECISION;
186 peer->burst = NSTAGE;
187 memcpy((char *)&pp->refid, REFID, 4);
189 up->leap_status = 0;
190 up->unit = (short) unit;
192 return (1);
197 * hopfserial_shutdown - shut down the clock
199 static void
200 hopfserial_shutdown (
201 int unit,
202 struct peer *peer
205 register struct hopfclock_unit *up;
206 struct refclockproc *pp;
208 pp = peer->procptr;
209 up = (struct hopfclock_unit *)pp->unitptr;
210 io_closeclock(&pp->io);
211 free(up);
217 * hopfserial_receive - receive data from the serial interface
220 static void
221 hopfserial_receive (
222 struct recvbuf *rbufp
225 struct hopfclock_unit *up;
226 struct refclockproc *pp;
227 struct peer *peer;
229 int synch; /* synchhronization indicator */
230 int DoW; /* Dow */
232 int day, month; /* ddd conversion */
235 * Initialize pointers and read the timecode and timestamp.
237 peer = (struct peer *)rbufp->recv_srcclock;
238 pp = peer->procptr;
239 up = (struct hopfclock_unit *)pp->unitptr;
241 if (up->rpt_next == 0 )
242 return;
245 up->rpt_next = 0; /* wait until next poll interval occur */
247 pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
249 if (pp->lencode == 0)
250 return;
252 sscanf(pp->a_lastcode,
253 #if 1
254 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */
255 #else
256 "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
257 #endif
258 &synch,
259 &DoW,
260 &pp->hour,
261 &pp->minute,
262 &pp->second,
263 &day,
264 &month,
265 &pp->year);
269 Validate received values at least enough to prevent internal
270 array-bounds problems, etc.
272 if((pp->hour < 0) || (pp->hour > 23) ||
273 (pp->minute < 0) || (pp->minute > 59) ||
274 (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
275 (day < 1) || (day > 31) ||
276 (month < 1) || (month > 12) ||
277 (pp->year < 0) || (pp->year > 99)) {
278 /* Data out of range. */
279 refclock_report(peer, CEVNT_BADREPLY);
280 return;
283 some preparations
285 pp->day = ymd2yd(pp->year,month,day);
286 pp->leap=0;
288 /* Year-2000 check! */
289 /* wrap 2-digit date into 4-digit */
291 if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */
292 pp->year += 1900;
294 /* preparation for timecode ntpq rl command ! */
296 #if 0
297 wsprintf(pp->a_lastcode,
298 "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d",
299 synch,
300 DoW,
301 day,
302 month,
303 pp->year,
304 pp->hour,
305 pp->minute,
306 pp->second);
308 pp->lencode = strlen(pp->a_lastcode);
309 if ((synch && 0xc) == 0 ){ /* time ok? */
310 refclock_report(peer, CEVNT_BADTIME);
311 pp->leap = LEAP_NOTINSYNC;
312 return;
314 #endif
316 * If clock has no valid status then report error and exit
318 if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */
319 refclock_report(peer, CEVNT_BADTIME);
320 pp->leap = LEAP_NOTINSYNC;
321 return;
325 * Test if time is running on internal quarz
326 * if CLK_FLAG1 is set, sychronize even if no radio operation
329 if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){
330 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
331 refclock_report(peer, CEVNT_BADTIME);
332 pp->leap = LEAP_NOTINSYNC;
333 return;
338 if (!refclock_process(pp)) {
339 refclock_report(peer, CEVNT_BADTIME);
340 return;
342 pp->lastref = pp->lastrec;
343 refclock_receive(peer);
345 #if 0
346 msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second);
347 #endif
349 record_clock_stats(&peer->srcadr, pp->a_lastcode);
351 return;
356 * hopfserial_poll - called by the transmit procedure
359 static void
360 hopfserial_poll (
361 int unit,
362 struct peer *peer
365 register struct hopfclock_unit *up;
366 struct refclockproc *pp;
367 pp = peer->procptr;
369 up = (struct hopfclock_unit *)pp->unitptr;
371 pp->polls++;
372 up->rpt_next = 1;
374 #if 0
375 record_clock_stats(&peer->srcadr, pp->a_lastcode);
376 #endif
378 return;
381 #else
382 int refclock_hopfser_bs;
383 #endif /* REFCLOCK */