]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/ntpd/refclock_tt560.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / ntpd / refclock_tt560.c
1 /*
2  * refclock_tt560 - clock driver for the TrueTime 560 IRIG-B decoder
3  */
4
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #if defined(REFCLOCK) && defined(CLOCK_TT560)
10
11 #include "ntpd.h"
12 #include "ntp_io.h"
13 #include "ntp_refclock.h"
14 #include "ntp_unixtime.h"
15 #include "sys/tt560_api.h"
16 #include "ntp_stdlib.h"
17
18 #include <stdio.h>
19 #include <ctype.h>
20
21 /*
22  * This driver supports the TrueTime 560 IRIG-B decoder for the PCI bus.
23  */ 
24
25 /*
26  * TT560 interface definitions
27  */
28 #define DEVICE           "/dev/tt560%d" /* device name and unit */
29 #define PRECISION       (-20)   /* precision assumed (1 us) */
30 #define REFID           "IRIG"  /* reference ID */
31 #define DESCRIPTION     "TrueTime 560 IRIG-B PCI Decoder"
32
33 /*
34  * Unit control structure
35  */
36 struct tt560unit {
37         tt_mem_space_t   *tt_mem;       /* mapped address of PCI board */
38         time_freeze_reg_t tt560rawt;    /* data returned from PCI board */
39 };
40
41 typedef union byteswap_u
42 {
43     unsigned int long_word;
44     unsigned char byte[4];
45 } byteswap_t;
46
47 /*
48  * Function prototypes
49  */
50 static  int     tt560_start     (int, struct peer *);
51 static  void    tt560_shutdown  (int, struct peer *);
52 static  void    tt560_poll      (int unit, struct peer *);
53
54 /*
55  * Transfer vector
56  */
57 struct  refclock refclock_tt560 = {
58         tt560_start,            /* clock_start    */
59         tt560_shutdown,         /* clock_shutdown */
60         tt560_poll,             /* clock_poll     */
61         noentry,                /* clock_control (not used) */
62         noentry,                /* clock_init    (not used) */
63         noentry,                /* clock_buginfo (not used) */
64         NOFLAGS                 /* clock_flags   (not used) */
65 };
66
67
68 /*
69  * tt560_start - open the TT560 device and initialize data for processing
70  */
71 static int
72 tt560_start(
73         int unit,
74         struct peer *peer
75         )
76 {
77         register struct tt560unit *up;
78         struct refclockproc *pp;
79         char    device[20];
80         int     fd;
81         caddr_t membase;
82
83         /*
84          * Open TT560 device
85          */
86         snprintf(device, sizeof(device), DEVICE, unit);
87         fd = open(device, O_RDWR);
88         if (fd == -1) {
89                 msyslog(LOG_ERR, "tt560_start: open of %s: %m", device);
90                 return (0);
91         }
92
93         /*
94          * Map the device registers into user space.
95          */
96         membase = mmap ((caddr_t) 0, TTIME_MEMORY_SIZE,
97                         PROT_READ | PROT_WRITE,
98                         MAP_SHARED, fd, (off_t)0);
99
100         if (membase == (caddr_t) -1) {
101                 msyslog(LOG_ERR, "tt560_start: mapping of %s: %m", device);
102                 (void) close(fd);
103                 return (0);
104         }
105
106         /*
107          * Allocate and initialize unit structure
108          */
109         if (!(up = (struct tt560unit *) emalloc(sizeof(struct tt560unit)))) {
110                 (void) close(fd);
111                 return (0);
112         }
113         memset((char *)up, 0, sizeof(struct tt560unit));
114         up->tt_mem = (tt_mem_space_t *)membase;
115         pp = peer->procptr;
116         pp->io.clock_recv = noentry;
117         pp->io.srcclock = (caddr_t)peer;
118         pp->io.datalen = 0;
119         pp->io.fd = fd;
120         pp->unitptr = (caddr_t)up;
121
122         /*
123          * Initialize miscellaneous peer variables
124          */
125         peer->precision = PRECISION;
126         pp->clockdesc = DESCRIPTION;
127         memcpy((char *)&pp->refid, REFID, 4);
128         return (1);
129 }
130
131
132 /*
133  * tt560_shutdown - shut down the clock
134  */
135 static void
136 tt560_shutdown(
137         int unit,
138         struct peer *peer
139         )
140 {
141         register struct tt560unit *up;
142         struct refclockproc *pp;
143
144         pp = peer->procptr;
145         up = (struct tt560unit *)pp->unitptr;
146         io_closeclock(&pp->io);
147         free(up);
148 }
149
150
151 /*
152  * tt560_poll - called by the transmit procedure
153  */
154 static void
155 tt560_poll(
156         int unit,
157         struct peer *peer
158         )
159 {
160         register struct tt560unit *up;
161         struct refclockproc       *pp;
162         time_freeze_reg_t         *tp;
163         tt_mem_space_t            *mp;
164
165         int i;
166         unsigned int *p_time_t, *tt_mem_t;
167
168         /*
169          * This is the main routine. It snatches the time from the TT560
170          * board and tacks on a local timestamp.
171          */
172         pp = peer->procptr;
173         up = (struct tt560unit *)pp->unitptr;
174         mp = up->tt_mem;
175         tp = &up->tt560rawt;
176
177         p_time_t = (unsigned int *)tp;
178         tt_mem_t = (unsigned int *)&mp->time_freeze_reg;
179
180         *tt_mem_t = 0;          /* update the time freeze register */
181                                 /* and copy time stamp to memory */
182         for (i=0; i < TIME_FREEZE_REG_LEN; i++) {
183             *p_time_t = byte_swap(*tt_mem_t);
184              p_time_t++;
185              tt_mem_t++;
186         }
187
188         get_systime(&pp->lastrec);
189         pp->polls++;
190
191         /*
192          * We get down to business, check the timecode format and decode
193          * its contents. If the timecode has invalid length or is not in
194          * proper format, we declare bad format and exit. Note: we
195          * can't use the sec/usec conversion produced by the driver,
196          * since the year may be suspect. All format error checking is
197          * done by the snprintf() and sscanf() routines.
198          */
199         snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
200             "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
201             tp->hun_day,  tp->tens_day,  tp->unit_day,
202                           tp->tens_hour, tp->unit_hour,
203                           tp->tens_min,  tp->unit_min,
204                           tp->tens_sec,  tp->unit_sec,
205             tp->hun_ms,   tp->tens_ms,   tp->unit_ms,
206             tp->hun_us,   tp->tens_us,   tp->unit_us,
207             tp->status);
208             pp->lencode = strlen(pp->a_lastcode);
209 #ifdef DEBUG
210         if (debug)
211                 printf("tt560: time %s timecode %d %s\n",
212                    ulfptoa(&pp->lastrec, 6), pp->lencode,
213                    pp->a_lastcode);
214 #endif
215         if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", 
216                   &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->usec)
217             != 5) {
218                 refclock_report(peer, CEVNT_BADTIME);
219                 return;
220         }
221         if ((tp->status & 0x6) != 0x6)
222                 pp->leap = LEAP_NOTINSYNC;
223         else
224                 pp->leap = LEAP_NOWARNING;
225         if (!refclock_process(pp)) {
226                 refclock_report(peer, CEVNT_BADTIME);
227                 return;
228         }
229         if (pp->coderecv == pp->codeproc) {
230                 refclock_report(peer, CEVNT_TIMEOUT);
231                 return;
232         }
233         record_clock_stats(&peer->srcadr, pp->a_lastcode);
234         refclock_receive(peer);
235 }
236
237 /******************************************************************
238  *
239  *  byte_swap
240  *
241  *  Inputs: 32 bit integer
242  *
243  *  Output: byte swapped 32 bit integer.
244  *
245  *  This routine is used to compensate for the byte alignment
246  *  differences between big-endian and little-endian integers.
247  *
248  ******************************************************************/
249 static unsigned int
250 byte_swap(unsigned int input_num)
251 {
252     byteswap_t    byte_swap;
253     unsigned char temp;
254
255     byte_swap.long_word = input_num;
256
257     temp              = byte_swap.byte[3];
258     byte_swap.byte[3] = byte_swap.byte[0];
259     byte_swap.byte[0] = temp;
260
261     temp              = byte_swap.byte[2];
262     byte_swap.byte[2] = byte_swap.byte[1];
263     byte_swap.byte[1] = temp;
264
265     return (byte_swap.long_word);
266 }
267
268 #else
269 int refclock_tt560_bs;
270 #endif /* REFCLOCK */