source: trunk/third/xntp/xntpd/refclock_bancomm.c @ 10832

Revision 10832, 20.9 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10831, which included commits to RCS files with non-trunk default branches.
Line 
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 */
41struct 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 */
91extern u_long current_time;     /* current time (s) */
92
93/*
94 * Imported from ntpd module
95 */
96extern int debug;               /* global debug flag */
97
98/*
99 * VME unit control structure.
100 */
101struct 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 */
136static struct vmeunit *vmeunits[MAXUNITS];
137static 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 */
143static l_fp fudgefactor[MAXUNITS];
144static u_char stratumtouse[MAXUNITS];
145static u_char sloppyclockflag[MAXUNITS];
146
147/*
148 * Function prototypes
149 */
150static  void    vme_init        P(());
151static  int     vme_start       P((u_int, struct peer *));
152static  void    vme_shutdown    P((int));
153static  void    vme_report_event        P((struct vmeunit *, int));
154static  void    vme_receive     P((struct recvbuf *));
155static  void    vme_poll        P((int unit, struct peer *));
156static  void    vme_control     P((u_int, struct refclockstat *, struct refclockstat *));
157static  void    vme_buginfo     P((int, struct refclockbug *));
158struct vmedate *get_datumtime();
159
160/*
161 * Transfer vector
162 */
163struct  refclock refclock_bancomm = {
164        vme_start, vme_shutdown, vme_poll,
165        vme_control, vme_init, vme_buginfo, NOFLAGS
166};
167
168int fd_vme;  /* file descriptor for ioctls */
169int regvalue;
170
171/*
172 * vme_init - initialize internal vme driver data
173 */
174static void
175vme_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 */
200static int
201vme_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, &regvalue ) )
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 */
299static void
300vme_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 */
328static void
329vme_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 */
352static void
353vme_receive(rbufp)
354        struct recvbuf *rbufp;
355{
356}
357
358/*
359 * vme_poll - called by the transmit procedure
360 */
361static void
362vme_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 */
463static void
464vme_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 */
539static void
540vme_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
573struct 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
623use 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
656use 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) */
677int refclock_bancomm_bs;
678#endif /* not (REFCLOCK && BANC) */
Note: See TracBrowser for help on using the repository browser.