refclock_bancomm.c [plain text]
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(REFCLOCK) && defined(CLOCK_BANC)
#include <stdio.h>
#include <syslog.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
#include "/etc/conf/machine/vme2.h"
#include "/etc/conf/h/io.h"
struct btfp_time
{
unsigned short btfp_time[5];
};
#define RUNLOCK _IO('X',19)
#define RCR0 _IOR('X',22,unsigned int)
#define WCR0 _IOW('X',23,unsigned int)
#define READTIME _IOR('X',32,struct btfp_time)
#define VMEFD "/dev/btfp0"
struct vmedate {
unsigned short year;
unsigned short doy;
unsigned short hr;
unsigned short mn;
unsigned short sec;
unsigned long frac;
unsigned short status;
};
#define MAXUNITS 2
#define BMAX 50
#define VMEPRECISION (-21)
#define USNOREFID "USNO"
#define VMEREFID "USNO"
#define VMEDESCRIPTION "USNO Master Clock 2"
#define VMEHSREFID 0x7f7f1000
#define GMT 0
struct vmeunit {
struct peer *peer;
struct refclockio io;
struct vmedate vmedata;
l_fp lastrec;
l_fp lastref;
char lastcode[BMAX];
u_short lencode;
u_long lasttime;
u_short unit;
u_short status;
u_short lastevent;
u_short year;
u_short day;
u_short hour;
u_short minute;
u_short second;
u_long usec;
u_long yearstart;
u_short leap;
u_long polls;
u_long noreply;
u_long coderecv;
u_long badformat;
u_long baddata;
u_long timestarted;
};
static struct vmeunit *vmeunits[MAXUNITS];
static u_char unitinuse[MAXUNITS];
static l_fp fudgefactor[MAXUNITS];
static u_char stratumtouse[MAXUNITS];
static u_char sloppyclockflag[MAXUNITS];
static void vme_init (void);
static int vme_start (u_int, struct peer *);
static void vme_shutdown (int);
static void vme_report_event (struct vmeunit *, int);
static void vme_receive (struct recvbuf *);
static void vme_poll (int unit, struct peer *);
static void vme_control (u_int, struct refclockstat *, struct refclockstat *);
static void vme_buginfo (int, struct refclockbug *);
struct vmedate *get_datumtime();
struct refclock refclock_bancomm = {
vme_start, vme_shutdown, vme_poll,
vme_control, vme_init, vme_buginfo, NOFLAGS
};
int fd_vme;
int regvalue;
static void
vme_init(void)
{
register int i;
for (i = 0; i < MAXUNITS; i++) {
fudgefactor[i].l_ui = 0;
fudgefactor[i].l_uf = 0;
stratumtouse[i] = 0;
sloppyclockflag[i] = 0;
}
}
static int
vme_start(
u_int unit,
struct peer *peer
)
{
register struct vmeunit *vme;
register int i;
int dummy;
char vmedev[20];
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "vme_start: unit %d invalid", unit);
return (0);
}
if (unitinuse[unit]) {
msyslog(LOG_ERR, "vme_start: unit %d in use", unit);
return (0);
}
#ifdef DEBUG
printf("Opening DATUM VME DEVICE \n");
#endif
if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
return (0);
}
else {
if( ioctl( fd_vme, RUNLOCK, &dummy ) )
msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
regvalue = 0;
if( ioctl( fd_vme, WCR0, ®value ) )
msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
}
if (vmeunits[unit] != 0) {
vme = vmeunits[unit];
} else {
for (i = 0; i < MAXUNITS; i++) {
if (!unitinuse[i] && vmeunits[i] != 0)
break;
}
if (i < MAXUNITS) {
vme = vmeunits[i];
vmeunits[i] = 0;
} else {
vme = (struct vmeunit *)
emalloc(sizeof(struct vmeunit));
}
}
bzero((char *)vme, sizeof(struct vmeunit));
vmeunits[unit] = vme;
vme->peer = peer;
vme->unit = (u_short)unit;
vme->timestarted = current_time;
vme->io.clock_recv = vme_receive;
vme->io.srcclock = (caddr_t)vme;
vme->io.datalen = 0;
vme->io.fd = fd_vme;
peer->precision = VMEPRECISION;
peer->stratum = stratumtouse[unit];
memcpy( (char *)&peer->refid, USNOREFID,4);
unitinuse[unit] = 1;
return (1);
}
static void
vme_shutdown(
int unit
)
{
register struct vmeunit *vme;
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit);
return;
}
if (!unitinuse[unit]) {
msyslog(LOG_ERR, "vme_shutdown: unit %d not in use", unit);
return;
}
vme = vmeunits[unit];
io_closeclock(&vme->io);
unitinuse[unit] = 0;
}
static void
vme_report_event(
struct vmeunit *vme,
int code
)
{
struct peer *peer;
peer = vme->peer;
if (vme->status != (u_short)code) {
vme->status = (u_short)code;
if (code != CEVNT_NOMINAL)
vme->lastevent = (u_short)code;
msyslog(LOG_INFO,
"clock %s event %x", ntoa(&peer->srcadr), code);
}
}
static void
vme_receive(
struct recvbuf *rbufp
)
{
}
static void
vme_poll(
int unit,
struct peer *peer
)
{
struct vmedate *tptr;
struct vmeunit *vme;
l_fp tstmp;
time_t tloc;
struct tm *tadr;
vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit *));
tptr = (struct vmedate *)emalloc(sizeof(struct vmedate *));
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "vme_poll: unit %d invalid", unit);
return;
}
if (!unitinuse[unit]) {
msyslog(LOG_ERR, "vme_poll: unit %d not in use", unit);
return;
}
vme = vmeunits[unit];
vme->polls++;
tptr = &vme->vmedata;
if ((tptr = get_datumtime()) == NULL ) {
vme_report_event(vme, CEVNT_BADREPLY);
return;
}
get_systime(&vme->lastrec);
vme->lasttime = current_time;
sprintf(vme->lastcode,
"%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0",
tptr->doy, tptr->hr, tptr->mn,
tptr->sec, tptr->frac, tptr->status);
record_clock_stats(&(vme->peer->srcadr), vme->lastcode);
vme->lencode = (u_short) strlen(vme->lastcode);
vme->day = tptr->doy;
vme->hour = tptr->hr;
vme->minute = tptr->mn;
vme->second = tptr->sec;
vme->usec = tptr->frac;
#ifdef DEBUG
if (debug)
printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n",
vme->day, vme->hour, vme->minute, vme->second,
vme->usec, tptr->status);
#endif
if (tptr->status ) {
vme_report_event(vme, CEVNT_BADREPLY);
return;
}
if (!clocktime(vme->day, vme->hour, vme->minute,
vme->second, GMT, vme->lastrec.l_ui,
&vme->yearstart, &vme->lastref.l_ui)) {
vme->baddata++;
vme_report_event(vme, CEVNT_BADTIME);
msyslog(LOG_ERR, "refclock_datum: bad data!!");
return;
}
TVUTOTSF(vme->usec, vme->lastref.l_uf);
tstmp = vme->lastref;
L_SUB(&tstmp, &vme->lastrec);
vme->coderecv++;
L_ADD(&tstmp, &(fudgefactor[vme->unit]));
refclock_receive(vme->peer);
}
static void
vme_control(
u_int unit,
struct refclockstat *in,
struct refclockstat *out
)
{
register struct vmeunit *vme;
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "vme_control: unit %d invalid)", unit);
return;
}
if (in != 0) {
if (in->haveflags & CLK_HAVETIME1)
fudgefactor[unit] = in->fudgetime1;
if (in->haveflags & CLK_HAVEVAL1) {
stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
if (unitinuse[unit]) {
struct peer *peer;
vme = vmeunits[unit];
peer = vme->peer;
peer->stratum = stratumtouse[unit];
if (stratumtouse[unit] <= 1)
memcpy( (char *)&peer->refid, USNOREFID,4);
else
peer->refid = htonl(VMEHSREFID);
}
}
if (in->haveflags & CLK_HAVEFLAG1) {
sloppyclockflag[unit] = in->flags & CLK_FLAG1;
}
}
if (out != 0) {
out->type = 15;
out->haveflags
= CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
out->clockdesc = VMEDESCRIPTION;
out->fudgetime1 = fudgefactor[unit];
out->fudgetime2.l_ui = 0;
out->fudgetime2.l_uf = 0;
out->fudgeval1 = (long)stratumtouse[unit];
out->fudgeval2 = 0;
out->flags = sloppyclockflag[unit];
if (unitinuse[unit]) {
vme = vmeunits[unit];
out->lencode = vme->lencode;
out->lastcode = vme->lastcode;
out->timereset = current_time - vme->timestarted;
out->polls = vme->polls;
out->noresponse = vme->noreply;
out->badformat = vme->badformat;
out->baddata = vme->baddata;
out->lastevent = vme->lastevent;
out->currentstatus = vme->status;
} else {
out->lencode = 0;
out->lastcode = "";
out->polls = out->noresponse = 0;
out->badformat = out->baddata = 0;
out->timereset = 0;
out->currentstatus = out->lastevent = CEVNT_NOMINAL;
}
}
}
static void
vme_buginfo(
int unit,
register struct refclockbug *bug
)
{
register struct vmeunit *vme;
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "vme_buginfo: unit %d invalid)", unit);
return;
}
if (!unitinuse[unit])
return;
vme = vmeunits[unit];
bug->nvalues = 11;
bug->ntimes = 5;
if (vme->lasttime != 0)
bug->values[0] = current_time - vme->lasttime;
else
bug->values[0] = 0;
bug->values[2] = (u_long)vme->year;
bug->values[3] = (u_long)vme->day;
bug->values[4] = (u_long)vme->hour;
bug->values[5] = (u_long)vme->minute;
bug->values[6] = (u_long)vme->second;
bug->values[7] = (u_long)vme->usec;
bug->values[9] = vme->yearstart;
bug->stimes = 0x1c;
bug->times[0] = vme->lastref;
bug->times[1] = vme->lastrec;
}
struct vmedate *
get_datumtime(void)
{
unsigned short status;
char cbuf[7];
struct vmedate *time_vme;
struct btfp_time vts;
time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
if( ioctl(fd_vme, READTIME, &vts))
msyslog(LOG_ERR, "get_datumtime error: %m");
#ifdef CHECK
sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
((vts.btfp_time[ 1 ] & 0xff00) >> 8));
if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) )
time_vme->doy = (unsigned short)atoi(cbuf);
else
time_vme->doy = (unsigned short) 0;
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff);
if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
time_vme->hr = (unsigned short)atoi(cbuf);
else
time_vme->hr = (unsigned short) 0;
sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8);
if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
time_vme->mn = (unsigned short)atoi(cbuf);
else
time_vme->mn = (unsigned short) 0;
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff);
if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
time_vme->sec = (unsigned short)atoi(cbuf);
else
time_vme->sec = (unsigned short) 0;
sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ],
vts.btfp_time[ 4 ]>>8);
if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2])
&& isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5]))
time_vme->frac = (u_long) atoi(cbuf);
else
time_vme->frac = (u_long) 0;
#else
sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
((vts.btfp_time[ 1 ] & 0xff00) >> 8));
time_vme->doy = (unsigned short)atoi(cbuf);
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff);
time_vme->hr = (unsigned short)atoi(cbuf);
sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8);
time_vme->mn = (unsigned short)atoi(cbuf);
sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff);
time_vme->sec = (unsigned short)atoi(cbuf);
sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ],
vts.btfp_time[ 4 ]>>8);
time_vme->frac = (u_long) atoi(cbuf);
#endif
status = (vts.btfp_time[0] & 0x0010) >>4;
time_vme->status = status;
if (status) {
return ((void *)NULL);
}
else
return (time_vme);
}
#else
int refclock_bancomm_bs;
#endif