1 | /* |
---|
2 | * refclock_bancomm.c - clock driver for the Datum/Bancomm |
---|
3 | * bc635VME Time and Frequency Processor. |
---|
4 | * R. Schmidt, Time Service, US Naval Obs. May 94 |
---|
5 | * modelled after the TPRO NTP driver. |
---|
6 | * |
---|
7 | * This requires the Datum HP-UX V9.01 kernel driver and the HP-UX vme2 |
---|
8 | * driver subsystem. It has been tested on an HP9000/747i at HP-UX 9.03. |
---|
9 | * There are no restrictions on release and use of the following code. |
---|
10 | * The refclock type has been defined as 16. |
---|
11 | * Installation of the Datum/Bancomm HPUX driver creates the device file |
---|
12 | * /dev/btfp0 |
---|
13 | * |
---|
14 | * These DEFS are included in the Makefile: |
---|
15 | * DEFS= -DHAVE_TERMIOS -DSYS_HPUX=9 |
---|
16 | * DEFS_LOCAL= -DREFCLOCK |
---|
17 | * CLOCKDEFS= -DBANC |
---|
18 | */ |
---|
19 | |
---|
20 | #ifdef HAVE_CONFIG_H |
---|
21 | #include <config.h> |
---|
22 | #endif |
---|
23 | |
---|
24 | #if defined(REFCLOCK) && defined(BANC) |
---|
25 | #include <stdio.h> |
---|
26 | #include <syslog.h> |
---|
27 | #include <ctype.h> |
---|
28 | #include <string.h> |
---|
29 | #include <strings.h> |
---|
30 | #include <sys/time.h> |
---|
31 | |
---|
32 | #include "ntpd.h" |
---|
33 | #include "ntp_io.h" |
---|
34 | #include "ntp_refclock.h" |
---|
35 | #include "ntp_unixtime.h" |
---|
36 | #include "ntp_stdlib.h" |
---|
37 | #include "/etc/conf/machine/vme2.h" |
---|
38 | #include "/etc/conf/h/io.h" |
---|
39 | |
---|
40 | /* STUFF BY RES */ |
---|
41 | struct btfp_time /* Structure for reading 5 time words */ |
---|
42 | /* in one ioctl(2) operation. */ |
---|
43 | { |
---|
44 | unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/ |
---|
45 | }; |
---|
46 | |
---|
47 | /***** Simple ioctl commands *****/ |
---|
48 | |
---|
49 | #define RUNLOCK _IO('X',19) /* Release Capture Lockout */ |
---|
50 | #define RCR0 _IOR('X',22,unsigned int) /* Read control register */ |
---|
51 | #define WCR0 _IOW('X',23,unsigned int) /* Write control register */ |
---|
52 | |
---|
53 | /***** Compound ioctl commands *****/ |
---|
54 | |
---|
55 | /* Read all 5 time words in one call. */ |
---|
56 | #define READTIME _IOR('X',32,struct btfp_time) |
---|
57 | #define VMEFD "/dev/btfp0" |
---|
58 | |
---|
59 | struct vmedate { /* structure returned by get_vmetime.c */ |
---|
60 | unsigned short year; |
---|
61 | unsigned short doy; |
---|
62 | unsigned short hr; |
---|
63 | unsigned short mn; |
---|
64 | unsigned short sec; |
---|
65 | unsigned long frac; |
---|
66 | unsigned short status; |
---|
67 | }; |
---|
68 | |
---|
69 | /* END OF STUFF FROM RES */ |
---|
70 | |
---|
71 | /* |
---|
72 | * Definitions |
---|
73 | */ |
---|
74 | #define MAXUNITS 2 /* max number of VME units */ |
---|
75 | #define BMAX 50 /* timecode buffer length */ |
---|
76 | |
---|
77 | /* |
---|
78 | * VME interface parameters. |
---|
79 | */ |
---|
80 | #define VMEPRECISION (-21) /* precision assumed (1 us) */ |
---|
81 | #define USNOREFID "USNO" /* or whatever */ |
---|
82 | #define VMEREFID "USNO" /* reference id */ |
---|
83 | #define VMEDESCRIPTION "USNO Master Clock 2" /* who we are */ |
---|
84 | #define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */ |
---|
85 | /* clock type 16 is used here */ |
---|
86 | #define GMT 0 /* hour offset from Greenwich */ |
---|
87 | |
---|
88 | /* |
---|
89 | * Imported from ntp_timer module |
---|
90 | */ |
---|
91 | extern u_long current_time; /* current time (s) */ |
---|
92 | |
---|
93 | /* |
---|
94 | * Imported from ntpd module |
---|
95 | */ |
---|
96 | extern int debug; /* global debug flag */ |
---|
97 | |
---|
98 | /* |
---|
99 | * VME unit control structure. |
---|
100 | */ |
---|
101 | struct vmeunit { |
---|
102 | struct peer *peer; /* associated peer structure */ |
---|
103 | struct refclockio io; /* given to the I/O handler */ |
---|
104 | struct vmedate vmedata; /* data returned from vme read */ |
---|
105 | l_fp lastrec; /* last local time */ |
---|
106 | l_fp lastref; /* last timecode time */ |
---|
107 | char lastcode[BMAX]; /* last timecode received */ |
---|
108 | u_short lencode; /* length of last timecode */ |
---|
109 | u_long lasttime; /* last time clock heard from */ |
---|
110 | u_short unit; /* unit number for this guy */ |
---|
111 | u_short status; /* clock status */ |
---|
112 | u_short lastevent; /* last clock event */ |
---|
113 | u_short year; /* year of eternity */ |
---|
114 | u_short day; /* day of year */ |
---|
115 | u_short hour; /* hour of day */ |
---|
116 | u_short minute; /* minute of hour */ |
---|
117 | u_short second; /* seconds of minute */ |
---|
118 | u_long usec; /* microsecond of second */ |
---|
119 | u_long yearstart; /* start of current year */ |
---|
120 | u_short leap; /* leap indicators */ |
---|
121 | /* |
---|
122 | * Status tallies |
---|
123 | */ |
---|
124 | u_long polls; /* polls sent */ |
---|
125 | u_long noreply; /* no replies to polls */ |
---|
126 | u_long coderecv; /* timecodes received */ |
---|
127 | u_long badformat; /* bad format */ |
---|
128 | u_long baddata; /* bad data */ |
---|
129 | u_long timestarted; /* time we started this */ |
---|
130 | }; |
---|
131 | |
---|
132 | /* |
---|
133 | * Data space for the unit structures. Note that we allocate these on |
---|
134 | * the fly, but never give them back. |
---|
135 | */ |
---|
136 | static struct vmeunit *vmeunits[MAXUNITS]; |
---|
137 | static u_char unitinuse[MAXUNITS]; |
---|
138 | |
---|
139 | /* |
---|
140 | * Keep the fudge factors separately so they can be set even |
---|
141 | * when no clock is configured. |
---|
142 | */ |
---|
143 | static l_fp fudgefactor[MAXUNITS]; |
---|
144 | static u_char stratumtouse[MAXUNITS]; |
---|
145 | static u_char sloppyclockflag[MAXUNITS]; |
---|
146 | |
---|
147 | /* |
---|
148 | * Function prototypes |
---|
149 | */ |
---|
150 | static void vme_init P(()); |
---|
151 | static int vme_start P((u_int, struct peer *)); |
---|
152 | static void vme_shutdown P((int)); |
---|
153 | static void vme_report_event P((struct vmeunit *, int)); |
---|
154 | static void vme_receive P((struct recvbuf *)); |
---|
155 | static void vme_poll P((int unit, struct peer *)); |
---|
156 | static void vme_control P((u_int, struct refclockstat *, struct refclockstat *)); |
---|
157 | static void vme_buginfo P((int, struct refclockbug *)); |
---|
158 | struct vmedate *get_datumtime(); |
---|
159 | |
---|
160 | /* |
---|
161 | * Transfer vector |
---|
162 | */ |
---|
163 | struct refclock refclock_bancomm = { |
---|
164 | vme_start, vme_shutdown, vme_poll, |
---|
165 | vme_control, vme_init, vme_buginfo, NOFLAGS |
---|
166 | }; |
---|
167 | |
---|
168 | int fd_vme; /* file descriptor for ioctls */ |
---|
169 | int regvalue; |
---|
170 | |
---|
171 | /* |
---|
172 | * vme_init - initialize internal vme driver data |
---|
173 | */ |
---|
174 | static void |
---|
175 | vme_init() |
---|
176 | { |
---|
177 | register int i; |
---|
178 | /* |
---|
179 | * Just zero the data arrays |
---|
180 | */ |
---|
181 | /* |
---|
182 | bzero((char *)vmeunits, sizeof vmeunits); |
---|
183 | bzero((char *)unitinuse, sizeof unitinuse); |
---|
184 | */ |
---|
185 | |
---|
186 | /* |
---|
187 | * Initialize fudge factors to default. |
---|
188 | */ |
---|
189 | for (i = 0; i < MAXUNITS; i++) { |
---|
190 | fudgefactor[i].l_ui = 0; |
---|
191 | fudgefactor[i].l_uf = 0; |
---|
192 | stratumtouse[i] = 0; |
---|
193 | sloppyclockflag[i] = 0; |
---|
194 | } |
---|
195 | } |
---|
196 | |
---|
197 | /* |
---|
198 | * vme_start - open the VME device and initialize data for processing |
---|
199 | */ |
---|
200 | static int |
---|
201 | vme_start(unit, peer) |
---|
202 | u_int unit; |
---|
203 | struct peer *peer; |
---|
204 | { |
---|
205 | register struct vmeunit *vme; |
---|
206 | register int i; |
---|
207 | int dummy; |
---|
208 | char vmedev[20]; |
---|
209 | |
---|
210 | /* |
---|
211 | * Check configuration info. |
---|
212 | */ |
---|
213 | if (unit >= MAXUNITS) { |
---|
214 | msyslog(LOG_ERR, "vme_start: unit %d invalid", unit); |
---|
215 | return (0); |
---|
216 | } |
---|
217 | if (unitinuse[unit]) { |
---|
218 | msyslog(LOG_ERR, "vme_start: unit %d in use", unit); |
---|
219 | return (0); |
---|
220 | } |
---|
221 | |
---|
222 | /* |
---|
223 | * Open VME device |
---|
224 | */ |
---|
225 | #ifdef DEBUG |
---|
226 | |
---|
227 | printf("Opening DATUM VME DEVICE \n"); |
---|
228 | #endif |
---|
229 | if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) { |
---|
230 | msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev); |
---|
231 | return (0); |
---|
232 | } |
---|
233 | else { /* Release capture lockout in case it was set from before. */ |
---|
234 | if( ioctl( fd_vme, RUNLOCK, &dummy ) ) |
---|
235 | msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m"); |
---|
236 | |
---|
237 | regvalue = 0; /* More esoteric stuff to do... */ |
---|
238 | if( ioctl( fd_vme, WCR0, ®value ) ) |
---|
239 | msyslog(LOG_ERR, "vme_start: WCR0 failed %m"); |
---|
240 | } |
---|
241 | |
---|
242 | /* |
---|
243 | * Allocate unit structure |
---|
244 | */ |
---|
245 | if (vmeunits[unit] != 0) { |
---|
246 | vme = vmeunits[unit]; /* The one we want is okay */ |
---|
247 | } else { |
---|
248 | for (i = 0; i < MAXUNITS; i++) { |
---|
249 | if (!unitinuse[i] && vmeunits[i] != 0) |
---|
250 | break; |
---|
251 | } |
---|
252 | if (i < MAXUNITS) { |
---|
253 | /* |
---|
254 | * Reclaim this one |
---|
255 | */ |
---|
256 | vme = vmeunits[i]; |
---|
257 | vmeunits[i] = 0; |
---|
258 | } else { |
---|
259 | vme = (struct vmeunit *) |
---|
260 | emalloc(sizeof(struct vmeunit)); |
---|
261 | } |
---|
262 | } |
---|
263 | bzero((char *)vme, sizeof(struct vmeunit)); |
---|
264 | vmeunits[unit] = vme; |
---|
265 | |
---|
266 | /* |
---|
267 | * Set up the structures |
---|
268 | */ |
---|
269 | vme->peer = peer; |
---|
270 | vme->unit = (u_short)unit; |
---|
271 | vme->timestarted = current_time; |
---|
272 | |
---|
273 | vme->io.clock_recv = vme_receive; |
---|
274 | vme->io.srcclock = (caddr_t)vme; |
---|
275 | vme->io.datalen = 0; |
---|
276 | vme->io.fd = fd_vme; |
---|
277 | |
---|
278 | /* |
---|
279 | * All done. Initialize a few random peer variables, then |
---|
280 | * return success. Note that root delay and root dispersion are |
---|
281 | * always zero for this clock. |
---|
282 | */ |
---|
283 | peer->precision = VMEPRECISION; |
---|
284 | peer->rootdelay = 0; |
---|
285 | peer->rootdispersion = 0; |
---|
286 | peer->stratum = stratumtouse[unit]; |
---|
287 | memcpy( (char *)&peer->refid, USNOREFID,4); |
---|
288 | |
---|
289 | /* peer->refid = htonl(VMEHSREFID); */ |
---|
290 | |
---|
291 | unitinuse[unit] = 1; |
---|
292 | return (1); |
---|
293 | } |
---|
294 | |
---|
295 | |
---|
296 | /* |
---|
297 | * vme_shutdown - shut down a VME clock |
---|
298 | */ |
---|
299 | static void |
---|
300 | vme_shutdown(unit) |
---|
301 | int unit; |
---|
302 | { |
---|
303 | register struct vmeunit *vme; |
---|
304 | |
---|
305 | if (unit >= MAXUNITS) { |
---|
306 | msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit); |
---|
307 | return; |
---|
308 | } |
---|
309 | if (!unitinuse[unit]) { |
---|
310 | msyslog(LOG_ERR, "vme_shutdown: unit %d not in use", unit); |
---|
311 | return; |
---|
312 | } |
---|
313 | |
---|
314 | /* |
---|
315 | * Tell the I/O module to turn us off. We're history. |
---|
316 | */ |
---|
317 | vme = vmeunits[unit]; |
---|
318 | io_closeclock(&vme->io); |
---|
319 | unitinuse[unit] = 0; |
---|
320 | } |
---|
321 | |
---|
322 | /* |
---|
323 | * vme_report_event - note the occurance of an event |
---|
324 | * |
---|
325 | * This routine presently just remembers the report and logs it, but |
---|
326 | * does nothing heroic for the trap handler. |
---|
327 | */ |
---|
328 | static void |
---|
329 | vme_report_event(vme, code) |
---|
330 | struct vmeunit *vme; |
---|
331 | int code; |
---|
332 | { |
---|
333 | struct peer *peer; |
---|
334 | |
---|
335 | peer = vme->peer; |
---|
336 | if (vme->status != (u_short)code) { |
---|
337 | vme->status = (u_short)code; |
---|
338 | if (code != CEVNT_NOMINAL) |
---|
339 | vme->lastevent = (u_short)code; |
---|
340 | msyslog(LOG_INFO, |
---|
341 | "clock %s event %x", ntoa(&peer->srcadr), code); |
---|
342 | } |
---|
343 | } |
---|
344 | |
---|
345 | |
---|
346 | /* |
---|
347 | * vme_receive - receive data from the VME device. |
---|
348 | * |
---|
349 | * Note: This interface would be interrupt-driven. We don't use that |
---|
350 | * now, but include a dummy routine for possible future adventures. |
---|
351 | */ |
---|
352 | static void |
---|
353 | vme_receive(rbufp) |
---|
354 | struct recvbuf *rbufp; |
---|
355 | { |
---|
356 | } |
---|
357 | |
---|
358 | /* |
---|
359 | * vme_poll - called by the transmit procedure |
---|
360 | */ |
---|
361 | static void |
---|
362 | vme_poll(unit, peer) |
---|
363 | int unit; |
---|
364 | struct peer *peer; |
---|
365 | { |
---|
366 | struct vmedate *tptr; |
---|
367 | struct vmeunit *vme; |
---|
368 | l_fp tstmp; |
---|
369 | time_t tloc; |
---|
370 | struct tm *tadr; |
---|
371 | |
---|
372 | |
---|
373 | vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit *)); |
---|
374 | tptr = (struct vmedate *)emalloc(sizeof(struct vmedate *)); |
---|
375 | |
---|
376 | |
---|
377 | if (unit >= MAXUNITS) { |
---|
378 | msyslog(LOG_ERR, "vme_poll: unit %d invalid", unit); |
---|
379 | return; |
---|
380 | } |
---|
381 | if (!unitinuse[unit]) { |
---|
382 | msyslog(LOG_ERR, "vme_poll: unit %d not in use", unit); |
---|
383 | return; |
---|
384 | } |
---|
385 | vme = vmeunits[unit]; /* Here is the structure */ |
---|
386 | vme->polls++; |
---|
387 | |
---|
388 | tptr = &vme->vmedata; |
---|
389 | if ((tptr = get_datumtime()) == NULL ) { |
---|
390 | vme_report_event(vme, CEVNT_BADREPLY); |
---|
391 | return; |
---|
392 | } |
---|
393 | |
---|
394 | get_systime(&vme->lastrec); |
---|
395 | vme->lasttime = current_time; |
---|
396 | |
---|
397 | /* |
---|
398 | * Get VME time and convert to timestamp format. |
---|
399 | * The year must come from the system clock. |
---|
400 | */ |
---|
401 | /* |
---|
402 | time(&tloc); |
---|
403 | tadr = gmtime(&tloc); |
---|
404 | tptr->year = (unsigned short)(tadr->tm_year + 1900); |
---|
405 | */ |
---|
406 | |
---|
407 | sprintf(vme->a_lastcode, |
---|
408 | "%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0", |
---|
409 | tptr->doy, tptr->hr, tptr->mn, |
---|
410 | tptr->sec, tptr->frac, tptr->status); |
---|
411 | |
---|
412 | record_clock_stats(&(vme->peer->srcadr), vme->a_lastcode); |
---|
413 | vme->lencode = (u_short) strlen(vme->a_lastcode); |
---|
414 | |
---|
415 | vme->day = tptr->doy; |
---|
416 | vme->hour = tptr->hr; |
---|
417 | vme->minute = tptr->mn; |
---|
418 | vme->second = tptr->sec; |
---|
419 | vme->usec = tptr->frac; |
---|
420 | |
---|
421 | #ifdef DEBUG |
---|
422 | if (debug) |
---|
423 | printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n", |
---|
424 | vme->day, vme->hour, vme->minute, vme->second, |
---|
425 | vme->usec, tptr->status); |
---|
426 | #endif |
---|
427 | if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ |
---|
428 | vme_report_event(vme, CEVNT_BADREPLY); |
---|
429 | return; |
---|
430 | } |
---|
431 | |
---|
432 | /* |
---|
433 | * Now, compute the reference time value. Use the heavy |
---|
434 | * machinery for the seconds and the millisecond field for the |
---|
435 | * fraction when present. If an error in conversion to internal |
---|
436 | * format is found, the program declares bad data and exits. |
---|
437 | * Note that this code does not yet know how to do the years and |
---|
438 | * relies on the clock-calendar chip for sanity. |
---|
439 | */ |
---|
440 | if (!clocktime(vme->day, vme->hour, vme->minute, |
---|
441 | vme->second, GMT, vme->lastrec.l_ui, |
---|
442 | &vme->yearstart, &vme->lastref.l_ui)) { |
---|
443 | vme->baddata++; |
---|
444 | vme_report_event(vme, CEVNT_BADTIME); |
---|
445 | msyslog(LOG_ERR, "refclock_datum: bad data!!"); |
---|
446 | return; |
---|
447 | } |
---|
448 | TVUTOTSF(vme->usec, vme->lastref.l_uf); |
---|
449 | tstmp = vme->lastref; |
---|
450 | |
---|
451 | L_SUB(&tstmp, &vme->lastrec); |
---|
452 | vme->coderecv++; |
---|
453 | |
---|
454 | L_ADD(&tstmp, &(fudgefactor[vme->unit])); |
---|
455 | |
---|
456 | refclock_receive(vme->peer, &tstmp, GMT, 0, |
---|
457 | &vme->lastrec, &vme->lastrec, vme->leap); |
---|
458 | } |
---|
459 | |
---|
460 | /* |
---|
461 | * vme_control - set fudge factors, return statistics |
---|
462 | */ |
---|
463 | static void |
---|
464 | vme_control(unit, in, out) |
---|
465 | u_int unit; |
---|
466 | struct refclockstat *in; |
---|
467 | struct refclockstat *out; |
---|
468 | { |
---|
469 | register struct vmeunit *vme; |
---|
470 | |
---|
471 | if (unit >= MAXUNITS) { |
---|
472 | msyslog(LOG_ERR, "vme_control: unit %d invalid)", unit); |
---|
473 | return; |
---|
474 | } |
---|
475 | |
---|
476 | if (in != 0) { |
---|
477 | if (in->haveflags & CLK_HAVETIME1) |
---|
478 | fudgefactor[unit] = in->fudgetime1; |
---|
479 | if (in->haveflags & CLK_HAVEVAL1) { |
---|
480 | stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf); |
---|
481 | if (unitinuse[unit]) { |
---|
482 | struct peer *peer; |
---|
483 | |
---|
484 | /* |
---|
485 | * Should actually reselect clock, but |
---|
486 | * will wait for the next timecode |
---|
487 | */ |
---|
488 | vme = vmeunits[unit]; |
---|
489 | peer = vme->peer; |
---|
490 | peer->stratum = stratumtouse[unit]; |
---|
491 | if (stratumtouse[unit] <= 1) |
---|
492 | memcpy( (char *)&peer->refid, USNOREFID,4); |
---|
493 | else |
---|
494 | peer->refid = htonl(VMEHSREFID); |
---|
495 | } |
---|
496 | } |
---|
497 | if (in->haveflags & CLK_HAVEFLAG1) { |
---|
498 | sloppyclockflag[unit] = in->flags & CLK_FLAG1; |
---|
499 | } |
---|
500 | } |
---|
501 | |
---|
502 | if (out != 0) { |
---|
503 | /* out->type = REFCLK_IRIG_VME; */ |
---|
504 | out->type = 15; /* made up by RES */ |
---|
505 | out->haveflags |
---|
506 | = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1; |
---|
507 | out->clockdesc = VMEDESCRIPTION; |
---|
508 | out->fudgetime1 = fudgefactor[unit]; |
---|
509 | out->fudgetime2.l_ui = 0; |
---|
510 | out->fudgetime2.l_uf = 0; |
---|
511 | out->fudgeval1 = (long)stratumtouse[unit]; |
---|
512 | out->fudgeval2 = 0; |
---|
513 | out->flags = sloppyclockflag[unit]; |
---|
514 | if (unitinuse[unit]) { |
---|
515 | vme = vmeunits[unit]; |
---|
516 | out->lencode = vme->lencode; |
---|
517 | strcpy(out->a_lastcode, vme->a_lastcode); |
---|
518 | out->timereset = current_time - vme->timestarted; |
---|
519 | out->polls = vme->polls; |
---|
520 | out->noresponse = vme->noreply; |
---|
521 | out->badformat = vme->badformat; |
---|
522 | out->baddata = vme->baddata; |
---|
523 | out->lastevent = vme->lastevent; |
---|
524 | out->currentstatus = vme->status; |
---|
525 | } else { |
---|
526 | out->lencode = 0; |
---|
527 | out->a_lastcode[0] = '\0'; |
---|
528 | out->polls = out->noresponse = 0; |
---|
529 | out->badformat = out->baddata = 0; |
---|
530 | out->timereset = 0; |
---|
531 | out->currentstatus = out->lastevent = CEVNT_NOMINAL; |
---|
532 | } |
---|
533 | } |
---|
534 | } |
---|
535 | |
---|
536 | /* |
---|
537 | * vme_buginfo - return clock dependent debugging info |
---|
538 | */ |
---|
539 | static void |
---|
540 | vme_buginfo(unit, bug) |
---|
541 | int unit; |
---|
542 | register struct refclockbug *bug; |
---|
543 | { |
---|
544 | register struct vmeunit *vme; |
---|
545 | |
---|
546 | if (unit >= MAXUNITS) { |
---|
547 | msyslog(LOG_ERR, "vme_buginfo: unit %d invalid)", unit); |
---|
548 | return; |
---|
549 | } |
---|
550 | |
---|
551 | if (!unitinuse[unit]) |
---|
552 | return; |
---|
553 | vme = vmeunits[unit]; |
---|
554 | |
---|
555 | bug->nvalues = 11; |
---|
556 | bug->ntimes = 5; |
---|
557 | if (vme->lasttime != 0) |
---|
558 | bug->values[0] = current_time - vme->lasttime; |
---|
559 | else |
---|
560 | bug->values[0] = 0; |
---|
561 | bug->values[2] = (u_long)vme->year; |
---|
562 | bug->values[3] = (u_long)vme->day; |
---|
563 | bug->values[4] = (u_long)vme->hour; |
---|
564 | bug->values[5] = (u_long)vme->minute; |
---|
565 | bug->values[6] = (u_long)vme->second; |
---|
566 | bug->values[7] = (u_long)vme->usec; |
---|
567 | bug->values[9] = vme->yearstart; |
---|
568 | bug->stimes = 0x1c; |
---|
569 | bug->times[0] = vme->lastref; |
---|
570 | bug->times[1] = vme->lastrec; |
---|
571 | } |
---|
572 | |
---|
573 | struct vmedate *get_datumtime() |
---|
574 | { |
---|
575 | unsigned short status; |
---|
576 | char cbuf[7]; |
---|
577 | struct vmedate *time_vme; |
---|
578 | struct btfp_time vts; |
---|
579 | time_vme = (struct vmedate *)malloc(sizeof(struct vmedate )); |
---|
580 | |
---|
581 | if( ioctl(fd_vme, READTIME, &vts)) |
---|
582 | msyslog(LOG_ERR, "get_datumtime error: %m"); |
---|
583 | |
---|
584 | /* if you want to actually check the validity of these registers, do a |
---|
585 | define of CHECK above this. I didn't find it necessary. - RES |
---|
586 | */ |
---|
587 | |
---|
588 | #ifdef CHECK |
---|
589 | |
---|
590 | /* Get doy */ |
---|
591 | sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + |
---|
592 | ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); |
---|
593 | |
---|
594 | if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) ) |
---|
595 | time_vme->doy = (unsigned short)atoi(cbuf); |
---|
596 | else |
---|
597 | time_vme->doy = (unsigned short) 0; |
---|
598 | |
---|
599 | /* Get hour */ |
---|
600 | sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff); |
---|
601 | |
---|
602 | if (isdigit(cbuf[0]) && isdigit(cbuf[1])) |
---|
603 | time_vme->hr = (unsigned short)atoi(cbuf); |
---|
604 | else |
---|
605 | time_vme->hr = (unsigned short) 0; |
---|
606 | |
---|
607 | /* Get minutes */ |
---|
608 | sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8); |
---|
609 | if (isdigit(cbuf[0]) && isdigit(cbuf[1])) |
---|
610 | time_vme->mn = (unsigned short)atoi(cbuf); |
---|
611 | else |
---|
612 | time_vme->mn = (unsigned short) 0; |
---|
613 | |
---|
614 | /* Get seconds */ |
---|
615 | sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff); |
---|
616 | |
---|
617 | if (isdigit(cbuf[0]) && isdigit(cbuf[1])) |
---|
618 | time_vme->sec = (unsigned short)atoi(cbuf); |
---|
619 | else |
---|
620 | time_vme->sec = (unsigned short) 0; |
---|
621 | |
---|
622 | /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can |
---|
623 | use the TVTOTSF function later on...*/ |
---|
624 | |
---|
625 | sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ], |
---|
626 | vts.btfp_time[ 4 ]>>8); |
---|
627 | |
---|
628 | if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) |
---|
629 | && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5])) |
---|
630 | time_vme->frac = (u_long) atoi(cbuf); |
---|
631 | else |
---|
632 | time_vme->frac = (u_long) 0; |
---|
633 | #else |
---|
634 | |
---|
635 | /* DONT CHECK just trust the card */ |
---|
636 | |
---|
637 | /* Get doy */ |
---|
638 | sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + |
---|
639 | ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); |
---|
640 | time_vme->doy = (unsigned short)atoi(cbuf); |
---|
641 | |
---|
642 | /* Get hour */ |
---|
643 | sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff); |
---|
644 | |
---|
645 | time_vme->hr = (unsigned short)atoi(cbuf); |
---|
646 | |
---|
647 | /* Get minutes */ |
---|
648 | sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8); |
---|
649 | time_vme->mn = (unsigned short)atoi(cbuf); |
---|
650 | |
---|
651 | /* Get seconds */ |
---|
652 | sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff); |
---|
653 | time_vme->sec = (unsigned short)atoi(cbuf); |
---|
654 | |
---|
655 | /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can |
---|
656 | use the TVTOTSF function later on...*/ |
---|
657 | |
---|
658 | sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ], |
---|
659 | vts.btfp_time[ 4 ]>>8); |
---|
660 | |
---|
661 | time_vme->frac = (u_long) atoi(cbuf); |
---|
662 | |
---|
663 | #endif /* CHECK */ |
---|
664 | |
---|
665 | /* Get status bit */ |
---|
666 | status = (vts.btfp_time[0] & 0x0010) >>4; |
---|
667 | time_vme->status = status; /* Status=0 if locked to ref. */ |
---|
668 | /* Status=1 if flywheeling */ |
---|
669 | if (status) { /* lost lock ? */ |
---|
670 | return ((void *)NULL); |
---|
671 | } |
---|
672 | else |
---|
673 | return (time_vme); |
---|
674 | } |
---|
675 | |
---|
676 | #else /* not (REFCLOCK && BANC) */ |
---|
677 | int refclock_bancomm_bs; |
---|
678 | #endif /* not (REFCLOCK && BANC) */ |
---|