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