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

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