home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
x
/
xntp3.zip
/
kernel
/
dcf77sync.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-09
|
31KB
|
1,385 lines
/*
* $Header: /src/NTP/v3/xntp/kernel/RCS/dcf77sync.c,v 2.8 1992/07/09 15:46:56 kardel XNTP-DCF-1 $
*
* $Id: dcf77sync.c,v 2.8 1992/07/09 15:46:56 kardel XNTP-DCF-1 $
*
* STREAMS module for reference clock
* (SunOS4.x)
*
* Copyright (c) 1989,1990,1991,1992
* Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
*
* This code can be modified and used freely provided that the
* credits remain intact.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Log: dcf77sync.c,v $
* Revision 2.8 1992/07/09 15:46:56 kardel
* fixed crash type bugs in RR strategy
* added format for ELV DCF7000
*
* Revision 2.7 1992/07/09 07:21:45 kardel
* comments and renaming to cvt_meinberg
*
* Revision 2.6 1992/07/08 11:41:17 kardel
* ifdef messup (VDDRV)
*
* Revision 2.5 1992/07/08 11:34:36 kardel
* RR search for conversion routines
* bad conversion statistics
*
* Revision 2.4 1992/07/06 13:58:40 kardel
* support for returning format code in DCFIOC_TIMECODE
*
* Revision 2.3 1992/07/06 10:03:57 kardel
* syncevt gets an additional parameter (local
* data structure)
*
* Revision 2.2 1992/07/05 22:14:09 kardel
* fixed memory allocation bug
*
* Revision 2.1 1992/07/05 21:31:40 kardel
* initial extendable multi protocol version
*
* Revision 1.7 1992/05/18 11:52:26 kardel
* using uniqtime for max precision (HIREZ timer on
* sun4c, SUN4_330, SUN4_470 - requires patch of
* badly compiled kern_clock.o - uniqtime routine)
*
* Revision 1.6 1992/03/13 16:46:17 kardel
* legal terms changed
*
* Revision 1.5 92/02/05 16:00:43 kardel
* renamed vddrv structure vd to dcf77sync_vd to avoid
* name clashed with commercial software
*
* Revision 1.4 92/01/15 15:57:42 kardel
* changed operation default to
* "just time stamp sampling"
*
* Revision 1.3 1991/12/16 12:52:25 kardel
* RCS version support for loadable driver
*
* Revision 1.2 1991/12/16 12:26:55 kardel
* RCS version support
*
* Revision 1.1 1991/12/16 10:58:23 kardel
* Initial revision
*
*/
#ifndef lint
static char rcsid[] = "$Id: dcf77sync.c,v 2.8 1992/07/09 15:46:56 kardel XNTP-DCF-1 $ FAU";
#endif
#include "sys/types.h"
#include "sys/conf.h"
#include "sys/buf.h"
#include "sys/param.h"
#include "sys/sysmacros.h"
#include "sys/errno.h"
#include "sys/time.h"
#include "sundev/mbvar.h"
#include "sun/autoconf.h"
#include "sys/stream.h"
#include "sys/stropts.h"
#include "sys/dir.h"
#include "sys/signal.h"
#include "sys/termios.h"
#include "sys/termio.h"
#include "sys/ttold.h"
#include "sys/user.h"
#include "sys/errno.h"
#include "sys/tty.h"
#ifdef VDDRV
#include "sun/vddrv.h"
#endif
#include "dcf77.h"
#include "dcf77sync.h"
#ifdef VDDRV
static unsigned int dcfbusy = 0;
/*--------------- loadable driver section -----------------------------*/
extern struct streamtab dcfinfo;
struct vdldrv dcf77sync_vd =
{
VDMAGIC_PSEUDO, /* nothing like a real driver - a STREAMS module */
"DCF-77 ", /* name this baby - keep room for revision number */
0, /* no mb_ctlr structure */
0, /* no md_driver structure */
0, /* no mb_device structure */
0, /* no controllers */
0, /* no devices */
0, /* no bdevsw entry */
0, /* no cdevsw entry */
0, /* choose any block number (don't you dare) */
0, /* choose any character number (see above) */
};
/*
* strings support usually not in kernel
*/
static int strlen(s)
register char *s;
{
register int c;
c = 0;
if (s)
{
while (*s++)
{
c++;
}
}
return c;
}
static char *strncpy(t, s, c)
register char *t;
register char *s;
register int c;
{
register char *T = t;
if (s && t)
{
while ((c-- > 0) && (*t++ = *s++))
;
}
return T;
}
/*
* driver init routine
* since no mechanism gets us into and out of the fmodsw, we have to
* do it ourselves
*/
/*ARGSUSED*/
int xxxinit(fc, vdp, vdi, vds)
unsigned int fc;
struct vddrv *vdp;
addr_t vdi;
struct vdstat *vds;
{
extern struct fmodsw fmodsw[];
extern int fmodcnt;
struct fmodsw *fm = fmodsw;
struct fmodsw *fmend = &fmodsw[fmodcnt];
struct fmodsw *ifm = (struct fmodsw *)0;
char *mname = dcfinfo.st_rdinit->qi_minfo->mi_idname;
switch (fc)
{
case VDLOAD:
vdp->vdd_vdtab = (struct vdlinkage *)&dcf77sync_vd;
/*
* now, jog fmodsw along scanning for an empty slot
* and deposit out name there
*/
while (fm <= fmend)
{
if (!strncmp(fm->f_name, mname, FMNAMESZ))
{
printf("vddrinit[%s]: STREAMS module already loaded.\n", mname);
return(EBUSY);
}
else
if ((ifm == (struct fmodsw *)0) &&
(fm->f_name[0] == '\0') && (fm->f_str == (struct streamtab *)0))
{
/*
* got one - so move in
*/
ifm = fm;
}
fm++;
}
if (ifm == (struct fmodsw *)0)
{
printf("vddrinit[%s]: no slot free for STREAMS module\n", mname);
return (ENOSPC);
}
else
{
static char revision[] = "$Revision: 2.8 $";
char *s, *S, *t;
strncpy(ifm->f_name, mname, FMNAMESZ);
ifm->f_name[FMNAMESZ] = '\0';
ifm->f_str = &dcfinfo;
/*
* copy RCS revision into Drv_name
*
* are we forcing RCS here to do things it was not built for ?
*/
s = revision;
while (*s && (*s != ' '))
{
s++;
}
if (*s == ' ') s++;
t = dcf77sync_vd.Drv_name;
while (*t && (*t != ' '))
{
t++;
}
if (*t == ' ') t++;
S = s;
while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.')))
{
S++;
}
if (*s && *t && (S > s))
{
if (strlen(t) >= (S - s))
{
(void) strncpy(t, s, S - s);
}
}
return (0);
}
break;
case VDUNLOAD:
if (dcfbusy > 0)
{
return (EBUSY);
}
else
{
while (fm <= fmend)
{
if (!strncmp(fm->f_name, mname, FMNAMESZ))
{
/*
* got it - kill entry
*/
fm->f_name[0] = '\0';
fm->f_str = (struct streamtab *)0;
fm++;
break;
}
fm++;
}
if (fm > fmend)
{
printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname);
return (ENXIO);
}
else
return (0);
}
case VDSTAT:
return (0);
default:
return (EIO);
}
return EIO;
}
#endif
/*--------------- stream module definition ----------------------------*/
static int dcfopen(), dcfclose(), dcfwput(), dcfrput(), dcfrsvc();
static struct module_info driverinfo =
{
0, /* module ID number */
"dcf", /* module name */
0, /* minimum accepted packet size */
INFPSZ, /* maximum accepted packet size */
1, /* high water mark - flow control */
0 /* low water mark - flow control */
};
static struct qinit rinit = /* read queue definition */
{
dcfrput, /* put procedure */
dcfrsvc, /* service procedure */
dcfopen, /* open procedure */
dcfclose, /* close procedure */
NULL, /* admin procedure - NOT USED FOR NOW */
&driverinfo, /* information structure */
NULL /* statistics */
};
static struct qinit winit = /* write queue definition */
{
dcfwput, /* put procedure */
NULL, /* service procedure */
NULL, /* open procedure */
NULL, /* close procedure */
NULL, /* admin procedure - NOT USED FOR NOW */
&driverinfo, /* information structure */
NULL /* statistics */
};
struct streamtab dcfinfo = /* stream info element for dpr driver */
{
&rinit, /* read queue */
&winit, /* write queue */
NULL, /* read mux */
NULL, /* write mux */
NULL /* module auto push */
};
/*--------------- driver data structures ----------------------------*/
int dcfdebug = ~0;
/*--------------- clock string parser data structures----------------*/
extern void uniqtime();
static void timepacket();
static int cvt_simple();
static int cvt_dcf7000();
static void syn_simple();
/*
* The Meinberg receiver every second sends a datagram of the following form
*
* <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
* pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3
* 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2
* <SOT> = '\002' ASCII start of text
* <EOT> = '\003' ASCII end of text
* <dd>,<mm>,<yy> = day, month, year(2 digits!!)
* <w> = day of week (sunday= 0)
* <hh>,<mm>,<ss> = hour, minute, second
* <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
* '#' if not PZF sychronisation available else ' ' for PZF 535
* <F> = '*' if time comes from internal quartz else ' '
* <D> = 'S' if daylight saving time is active else ' '
* <A> = '!' during the hour preceeding an daylight saving time
* start/end change
*/
/*
* field location structure (Meinberg clocks/simple format)
*/
#define O_DAY 0
#define O_MONTH 1
#define O_YEAR 2
#define O_HOUR 3
#define O_MIN 4
#define O_SEC 5
#define O_WDAY 6
#define O_FLAGS 7
#define O_ZONE 8
#define O_COUNT (O_ZONE+1)
#define MBG_EXTENDED 0x00000001
static struct format
{
struct foff
{
char offset; /* offset into buffer */
char length; /* length of field */
} field_offsets[O_COUNT];
char *fixed_string; /* string with must be chars (blanks = wildcards) */
unsigned long flags;
} formats[] =
{
{
{
{ 3, 2}, { 6, 2}, { 9, 2}, { 18, 2}, { 21, 2}, { 24, 2}, { 14, 1}, { 27, 4}, { 29, 1 }
},
"\2D: . . ;T: ;U: . . ; \3",
0
},
{ /*
* preliminary definition - will change
* when actual format is known
*/
{
{ 3, 2}, { 6, 2}, { 9, 2}, { 18, 2}, { 21, 2}, { 24, 2}, { 14, 1}, { 27, 4}, { 29, 1 }
},
"\2 . . ; ; . . ; \3",
MBG_EXTENDED
},
{ /* ELV DCF7000 */
{
{ 6, 2}, { 3, 2}, { 0, 2}, { 12, 2}, { 15, 2}, { 18, 2}, { 9, 2}, { 21, 2}, { 0, 0 }
},
" - - - - - - - \r",
0
}
};
/*
* format definitions
*/
static clockformat_t clockformats[] =
{
{
cvt_simple,
syn_simple,
(void *)&formats[0],
"Meinberg Standard",
32,
F_START|F_END|SYNC_END,
'\2',
'\3',
0
},
{
cvt_simple,
syn_simple,
(void *)&formats[1],
"Meinberg Extended",
32,
F_START|F_END|SYNC_END,
'\2',
'\3',
0
},
{
cvt_dcf7000,
syn_simple,
(void *)&formats[2],
"ELV DCF7000",
24,
F_END|SYNC_END,
'\0',
'\r',
0
}
};
static nformats = sizeof(clockformats) / sizeof(clockformats[0]);
/*--------------- module implementation -----------------------------*/
/*ARGSUSED*/
static int dcfopen(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag;
int sflag;
{
register mblk_t *mp;
register dcf_t *dcf;
register int i;
register int f = 0;
dcfprintf(DD_OPEN,("dcf77: OPEN\n"));
if (sflag != MODOPEN)
{ /* open only for modules */
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - not MODOPEN\n"));
return OPENFAIL;
}
if (q->q_ptr != (caddr_t)NULL)
{
u.u_error = EBUSY;
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - EXCLUSIVE ONLY\n"));
return OPENFAIL;
}
#ifdef VDDRV
dcfbusy++;
#endif
q->q_ptr = (caddr_t)kmem_alloc(sizeof(dcf_t));
WR(q)->q_ptr = q->q_ptr;
dcf = (dcf_t *) q->q_ptr;
bzero((caddr_t)dcf, sizeof(*dcf));
dcf->dcf_queue = q;
/*
* gather bitmaps of possible start and end values
*/
for (i=0; i < nformats; i++)
{
if (clockformats[i].flags & F_START)
{
if (dcf->dcf_endsym[clockformats[i].startsym / 8] & (1 << (clockformats[i].startsym % 8)))
{
#ifdef VDDRV
dcfbusy--;
#endif
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - START/END conflict\n"));
return OPENFAIL;
}
else
{
dcf->dcf_startsym[clockformats[i].startsym / 8] |= (1 << (clockformats[i].startsym % 8));
f = 1;
}
}
if (clockformats[i].flags & F_END)
{
if (dcf->dcf_startsym[clockformats[i].endsym / 8] & (1 << (clockformats[i].endsym % 8)))
{
#ifdef VDDRV
dcfbusy--;
#endif
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - END/START conflict\n"));
return OPENFAIL;
}
else
{
dcf->dcf_endsym[clockformats[i].endsym / 8] |= (1 << (clockformats[i].endsym % 8));
f = 1;
}
}
if (clockformats[i].flags & SYNC_CHAR)
{
dcf->dcf_syncsym[clockformats[i].syncsym / 8] |= (1 << (clockformats[i].syncsym % 8));
}
dcf->dcf_syncflags |= clockformats[i].flags & (SYNC_START|SYNC_END|SYNC_CHAR);
if (dcf->dcf_dsize < clockformats[i].length)
dcf->dcf_dsize = clockformats[i].length;
}
if (!f)
{
/*
* need at least one start or end symbol
*/
#ifdef VDDRV
dcfbusy--;
#endif
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - no START/END characters\n"));
return OPENFAIL;
}
dcf->dcf_data = (char *)kmem_alloc(dcf->dcf_dsize * 2 + 2);
if (!dcf->dcf_data)
{
/*
* can never happen - panics first
*/
kmem_free((caddr_t)dcf, sizeof(dcf_t));
#ifdef VDDRV
dcfbusy--;
#endif
return OPENFAIL;
}
/*
* leave room for '\0'
*/
dcf->dcf_ldata = dcf->dcf_data + dcf->dcf_dsize + 1;
dcf->dcf_lformat = 0;
dcf->dcf_badformat = 0;
mp = allocb(sizeof(struct stroptions), BPRI_MED);
if (mp)
{
struct stroptions *str = (struct stroptions *)mp->b_rptr;
str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT;
str->so_readopt = RMSGD;
str->so_hiwat = sizeof(dcftime_t);
str->so_lowat = 0;
mp->b_datap->db_type = M_SETOPTS;
mp->b_wptr += sizeof(struct stroptions);
putnext(q, mp);
if (putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM))
{
dcfprintf(DD_OPEN,("dcf77: OPEN - SUCCEEDED\n"));
return 1;
}
else
{
#ifdef VDDRV
dcfbusy--;
#endif
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - no MC_SERVICEIMM\n"));
return OPENFAIL;
}
}
else
{
#ifdef VDDRV
dcfbusy--;
#endif
dcfprintf(DD_OPEN,("dcf77: OPEN - FAILED - no MEMORY for allocb\n"));
return OPENFAIL;
}
}
/*ARGSUSED*/
static int dcfclose(q, flags)
queue_t *q;
int flags;
{
register dcf_t *dcf = (dcf_t *)q->q_ptr;
dcfprintf(DD_CLOSE,("dcf77: CLOSE\n"));
if (dcf->dcf_data)
kmem_free((caddr_t)dcf->dcf_data, dcf->dcf_dsize * 2 + 2);
kmem_free((caddr_t)dcf, sizeof(dcf_t));
q->q_ptr = (caddr_t)NULL;
WR(q)->q_ptr = (caddr_t)NULL;
#ifdef VDDRV
dcfbusy--;
#endif
}
static dcfrsvc(q)
queue_t *q;
{
mblk_t *mp;
while (mp = getq(q))
{
if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
{
putnext(q, mp);
dcfprintf(DD_RSVC,("dcf77: RSVC - putnext\n"));
}
else
{
putbq(q, mp);
dcfprintf(DD_RSVC,("dcf77: RSVC - flow control wait\n"));
break;
}
}
}
static int dcfwput(q, mp)
queue_t *q;
register mblk_t *mp;
{
register int ok = 1;
struct iocblk *iocp;
dcf_t *dcf = (dcf_t *)q->q_ptr;
dcfprintf(DD_WPUT,("dcf77: dcfwput\n"));
switch (mp->b_datap->db_type)
{
default:
putnext(q, mp);
break;
case M_IOCTL:
iocp = (struct iocblk *)mp->b_rptr;
switch (iocp->ioc_cmd)
{
default:
dcfprintf(DD_WPUT,("dcf77: dcfwput - forward M_IOCTL\n"));
putnext(q, mp);
break;
case DCFIOC_SETSTAT:
case DCFIOC_GETSTAT:
case DCFIOC_TIMECODE:
case DCFIOC_GETFMT:
if (iocp->ioc_count == sizeof(dcfctl_t))
{
dcfctl_t *dct = (dcfctl_t *)mp->b_cont->b_rptr;
switch (iocp->ioc_cmd)
{
case DCFIOC_GETSTAT:
dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_GETSTAT\n"));
dct->dcfstatus.flags = dcf->dcf_flags;
break;
case DCFIOC_SETSTAT:
dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_SETSTAT\n"));
dcf->dcf_flags = dct->dcfstatus.flags;
break;
case DCFIOC_TIMECODE:
dct->dcfgettc.dcf_state = dcf->dcf_lstate;
dct->dcfgettc.dcf_format = dcf->dcf_lformat;
/*
* move out current bad packet count
* user program is expected to sum these up
* this is not a problem, as "dcf" module are
* exclusive open only
*/
dct->dcfgettc.dcf_badformat = dcf->dcf_badformat;
dcf->dcf_badformat = 0;
if (dcf->dcf_ldsize <= DCF_TCMAX)
{
dct->dcfgettc.dcf_count = dcf->dcf_ldsize;
bcopy(dcf->dcf_ldata, dct->dcfgettc.dcf_buffer, dct->dcfgettc.dcf_count);
dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_TIMECODE - ok\n"));
}
else
{
dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_TIMECODE - FAILED\n"));
ok = 0;
}
break;
case DCFIOC_GETFMT:
if (dct->dcfgetformat.dcf_format < nformats &&
strlen(clockformats[dct->dcfgetformat.dcf_format].name) <= DCF_TCMAX)
{
dct->dcfgetformat.dcf_count = strlen(clockformats[dct->dcfgetformat.dcf_format].name)+1;
bcopy(clockformats[dct->dcfgetformat.dcf_format].name, dct->dcfgetformat.dcf_buffer, dct->dcfgetformat.dcf_count);
dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_GETFMT - ok\n"));
}
else
{
dcfprintf(DD_WPUT,("dcf77: dcfwput - DCFIOC_GETFMT - FAILED\n"));
ok = 0;
}
break;
}
mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK;
}
else
{
mp->b_datap->db_type = M_IOCNAK;
}
qreply(q, mp);
break;
}
}
}
static int rdchar(mp)
register mblk_t **mp;
{
while (*mp != (mblk_t *)NULL)
{
if ((*mp)->b_wptr - (*mp)->b_rptr)
{
return (int)(*(unsigned char *)((*mp)->b_rptr++) & 0x7F);
}
else
{
register mblk_t *mmp = *mp;
*mp = (*mp)->b_cont;
freeb(mmp);
}
}
return -1;
}
static int dcfrput(q, mp)
queue_t *q;
mblk_t *mp;
{
switch (mp->b_datap->db_type)
{
default:
dcfprintf(DD_RPUT,("dcf77: dcfrput - forward\n"));
if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
{
putnext(q, mp);
}
else
putq(q, mp);
break;
case M_DATA:
{
register dcf_t * dcf = (dcf_t *)q->q_ptr;
struct timeval ctime;
/*
* get time on packet delivery
*/
uniqtime(&ctime);
dcfprintf(DD_RPUT,("dcf77: dcfrput - M_DATA\n"));
/*
* parse packet looking for start an end characters
*/
while (mp != (mblk_t *)NULL)
{
int ch = rdchar(&mp);
if (ch != -1)
{
if ((dcf->dcf_syncflags & SYNC_CHAR) &&
(dcf->dcf_syncsym[ch / 8] & (1 << (ch % 8))))
{
register int i;
/*
* got a sync event - call sync routine
*/
for (i = 0; i < nformats; i++)
{
if ((clockformats[i].flags & SYNC_CHAR) &&
(clockformats[i].syncsym == ch))
{
clockformats[i].syncevt(dcf, &ctime, clockformats[i].data, SYNC_CHAR);
dcfprintf(DD_RPUT,("dcf77: dcfrput - SYNC (%d - CHAR)\n", i));
}
}
}
if (dcf->dcf_startsym[ch / 8] & (1 << (ch % 8)))
{
register int i;
/*
* packet start - re-fill buffer
*/
if (dcf->dcf_index)
{
/*
* filled buffer - thus not end charcter found
* do processing now
*/
dcf->dcf_data[dcf->dcf_index] = '\0';
bcopy(dcf->dcf_data, dcf->dcf_ldata, dcf->dcf_index+1);
dcf->dcf_ldsize = dcf->dcf_index+1;
dcfprintf(DD_RPUT,("dcf77: dcfrput - PROCESS (colliding START)\n", i));
timepacket(dcf);
}
/*
* could be a sync event - call sync routine if needed
*/
if (dcf->dcf_syncflags & SYNC_START)
for (i = 0; i < nformats; i++)
{
if (clockformats[i].flags & SYNC_START)
{
clockformats[i].syncevt(dcf, &ctime, clockformats[i].data, SYNC_START);
dcfprintf(DD_RPUT,("dcf77: dcfrput - SYNC (%d - START)\n", i));
}
}
dcf->dcf_index = 1;
dcf->dcf_data[0] = ch;
}
else
{
register int i;
if (dcf->dcf_index < dcf->dcf_dsize)
{
/*
* collect into buffer
*/
dcf->dcf_data[dcf->dcf_index++] = ch;
}
if ((dcf->dcf_endsym[ch / 8] & (1 << (ch % 8))) ||
(dcf->dcf_index >= dcf->dcf_dsize))
{
/*
* packet end - process buffer
*/
if (dcf->dcf_syncflags & SYNC_END)
for (i = 0; i < nformats; i++)
{
if (clockformats[i].flags & SYNC_END)
{
clockformats[i].syncevt(dcf, &ctime, clockformats[i].data, SYNC_END);
dcfprintf(DD_RPUT,("dcf77: dcfrput - SYNC (%d - END)\n", i));
}
}
dcf->dcf_data[dcf->dcf_index] = '\0';
bcopy(dcf->dcf_data, dcf->dcf_ldata, dcf->dcf_index+1);
dcf->dcf_ldsize = dcf->dcf_index+1;
dcfprintf(DD_RPUT,("dcf77: dcfrput - PROCESS (END)\n"));
timepacket(dcf);
dcf->dcf_index = 0;
}
}
}
}
break;
}
}
}
/*---------- conversion implementation --------------------*/
/*
* convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
*/
#define dysize(x) ((x) % 4 ? 365 : ((x % 400) ? 365 :366))
static time_t dcf_to_unixtime(clock)
clocktime_t *clock;
{
static int days_of_month[] =
{
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
register int i;
time_t t;
if (clock->year < 100)
clock->year += 1900;
if (clock->year < 1970)
clock->year += 100; /* XXX this will do it till <2070 */
if (clock->year < 0)
return -1;
t = (clock->year - 1970) * 365;
t += clock->year / 4 - 1970 / 4;
t -= clock->year / 400 - 1970 / 400;
/* month */
if (clock->month <= 0 || clock->month > 12)
{
return -1; /* bad month */
}
/* adjust leap year */
if (clock->month >= 3 && dysize(clock->year) == 366)
t++;
for (i = 1; i < clock->month; i++)
{
t += days_of_month[i];
}
/* day */
if (clock->day < 1 || ((clock->month == 2 && dysize(clock->year) == 366) ?
clock->day > 29 : clock->day > days_of_month[clock->month]))
{
return -1; /* bad day */
}
t += clock->day - 1;
/* hour */
if (clock->hour < 0 || clock->hour >= 24)
{
return -1; /* bad hour */
}
t = 24 * t + clock->hour;
/* min */
if (clock->minute < 0 || clock->minute > 59)
{
return -1; /* bad min */
}
t = 60*t + clock->minute;
/* sec */
t += clock->utcoffset; /* warp to UTC */
if (clock->second < 0 || clock->second > 60) /* allow for LEAPs */
{
return -1; /* bad sec */
}
t = 60*t + clock->second;
/* done */
return t;
}
/*--------------- format conversion -----------------------------------*/
static int stoi(s, zp, cnt)
char *s;
long *zp;
int cnt;
{
char *b = s;
int f,z,v;
char c;
f=z=v=0;
while(*s == ' ')
s++;
if (*s == '-')
{
s++;
v = 1;
}
else
if (*s == '+')
s++;
for(;;)
{
c = *s++;
if (c == '\0' || c < '0' || c > '9' || (cnt && ((s-b) > cnt)))
{
if (f == 0)
{
return(-1);
}
if (v)
z = -z;
*zp = z;
return(0);
}
z = (z << 3) + (z << 1) + ( c - '0' );
f=1;
}
}
#define CVT_NONE 0
#define CVT_FAIL 1
#define CVT_OK 2
static strok(s, m)
char *s;
char *m;
{
if (!s || !m)
return 0;
while(*s && *m)
{
if ((*m == ' ') ? 1 : (*s == *m))
{
s++;
m++;
}
else
{
return 0;
}
}
return !*m;
}
/*
* cvt_simple
*
* convert simple type format
*/
static cvt_simple(buffer, format, clock)
register char *buffer;
register struct format *format;
register clocktime_t *clock;
{
if (!strok(buffer, format->fixed_string))
{
return CVT_NONE;
}
else
{
if (stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day,
format->field_offsets[O_DAY].length) ||
stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month,
format->field_offsets[O_MONTH].length) ||
stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year,
format->field_offsets[O_YEAR].length) ||
stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour,
format->field_offsets[O_HOUR].length) ||
stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute,
format->field_offsets[O_MIN].length) ||
stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second,
format->field_offsets[O_SEC].length))
{
return CVT_FAIL;
}
else
{
char *f = &buffer[format->field_offsets[O_FLAGS].offset];
clock->flags = 0;
clock->usecond = 0;
switch (buffer[format->field_offsets[O_ZONE].offset])
{
case ' ':
clock->utcoffset = -60; /* MET */
break;
case 'S':
clock->utcoffset = -120; /* MED */
clock->flags |= DCFB_DST;
break;
case 'U':
clock->utcoffset = 0; /* UTC */
clock->flags |= DCFB_UTC;
break;
default:
return CVT_FAIL;
}
if (f[0] == '#')
clock->flags |= DCFB_POWERUP;
if (f[1] == '*')
clock->flags |= DCFB_NOSYNC;
if (f[3] == '!')
clock->flags |= DCFB_ANNOUNCE;
if (format->flags & MBG_EXTENDED)
{
clock->flags |= DCFB_S_LEAP;
clock->flags |= DCFB_S_LOCATION;
if (f[4] == 'L')
clock->flags |= DCFB_LEAP;
if (f[5] == 'R')
clock->flags |= DCFB_ALTERNATE;
}
return CVT_OK;
}
}
}
/*
* cvt_dcf7000
*
* convert dcf7000 type format
*/
static cvt_dcf7000(buffer, format, clock)
register char *buffer;
register struct format *format;
register clocktime_t *clock;
{
if (!strok(buffer, format->fixed_string))
{
return CVT_NONE;
}
else
{
if (stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day,
format->field_offsets[O_DAY].length) ||
stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month,
format->field_offsets[O_MONTH].length) ||
stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year,
format->field_offsets[O_YEAR].length) ||
stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour,
format->field_offsets[O_HOUR].length) ||
stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute,
format->field_offsets[O_MIN].length) ||
stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second,
format->field_offsets[O_SEC].length))
{
return CVT_FAIL;
}
else
{
char *f = &buffer[format->field_offsets[O_FLAGS].offset];
int flags;
clock->flags = 0;
clock->usecond = 0;
if (stoi(f, &flags, format->field_offsets[O_FLAGS].length))
{
return CVT_FAIL;
}
else
{
if (flags & 0x1)
clock->utcoffset = -120;
else
clock->utcoffset = -60;
if (flags & 0x2)
clock->flags |= DCFB_ANNOUNCE;
if (flags & 0x4)
clock->flags |= DCFB_NOSYNC;
}
return CVT_OK;
}
}
}
/*
* syn_simple
*
* handle a sync time stamp
*/
/*ARGSUSED*/
static void syn_simple(dcf, tv, format, why)
register dcf_t *dcf;
register struct timeval *tv;
register struct format *format;
register unsigned long why;
{
dcf->dcf_stime = *tv;
}
/*
* timepacket
*
* process a data packet
*/
static void timepacket(dcf)
register dcf_t *dcf;
{
register int s, k;
register unsigned short format;
register long mean;
register time_t t;
long delta[DCF_DELTA];
dcftime_t dtime;
clocktime_t clock;
mblk_t *nmp;
/*
* find correct conversion routine
* and convert time packet
* RR search starting at last successful conversion routine
*/
k = 0;
format = dcf->dcf_lformat;
if (nformats) /* very careful ... */
{
do
{
switch (clockformats[format].convert(dcf->dcf_data, clockformats[format].data, &clock))
{
case CVT_FAIL:
dcf->dcf_badformat++;
/*
* may be too often ... but is nice to know when it happens
*/
printf("dcf77: \"%s\" failed to convert\n", clockformats[format].name);
/*FALLTHROUGH*/
case CVT_NONE:
format++;
break;
case CVT_OK:
k = 1;
break;
default:
/* shouldn't happen */
printf("dcf77: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format].name);
return;
}
if (format >= nformats)
format = 0;
}
while (!k && (format != dcf->dcf_lformat));
}
if (!k)
{
printf("dcf77: time format \"%s\" not convertable\n", dcf->dcf_data);
return;
}
if ((t = dcf_to_unixtime(&clock)) == -1)
{
printf("dcf77: bad time format \"%s\"\n", dcf->dcf_data);
return;
}
dcf->dcf_lformat = format;
/*
* filtering (median) if requested
*/
if (dcf->dcf_flags & DCF_STAT_FILTER)
{
dcf->dcf_delta[dcf->dcf_dindex] = s = (t - dcf->dcf_stime.tv_sec) * 1000000 - dcf->dcf_stime.tv_usec + clock.usecond;
dcf->dcf_dindex = (dcf->dcf_dindex + 1) % DCF_DELTA;
bcopy((caddr_t)dcf->dcf_delta, (caddr_t)delta, sizeof(delta));
for (s = 0; s < DCF_DELTA; s++)
for (k = s+1; k < DCF_DELTA; k++)
{
if (delta[s] > delta[k])
{
register long tmp;
tmp = delta[k];
delta[k] = delta[s];
delta[s] = tmp;
}
}
mean = 0;
for (s = DCF_DELTA / 2 - DCF_DELTA / 4; s < (DCF_DELTA / 2 + DCF_DELTA / 4); s++)
{
mean += delta[s];
}
mean /= DCF_DELTA / 2;
dcf->dcf_usecerror = mean;
/*
* assumption: DCF_DELTA / 2 >= 1
*/
dcf->dcf_usecdisp = delta[DCF_DELTA / 2 + DCF_DELTA / 4 - 1] -
delta[DCF_DELTA / 2 - DCF_DELTA / 4];
}
else
{
dcf->dcf_usecerror = (t - dcf->dcf_stime.tv_sec) * 1000000 - dcf->dcf_stime.tv_usec + clock.usecond;
dcf->dcf_usecdisp = 0;
}
/*
* register sample time
*/
dtime.dcf_stime = dcf->dcf_stime;
/*
* time stamp
*/
dtime.dcf_time.tv_sec = t;
dtime.dcf_time.tv_usec = clock.usecond;
/*
* derived usec error
*/
dtime.dcf_usecerror = dcf->dcf_usecerror;
/*
* filter statistics
*/
dtime.dcf_usecdisp = dcf->dcf_usecdisp;
dtime.dcf_flags = dcf->dcf_flags;
dtime.dcf_format = format;
dtime.dcf_state = clock.flags;
dcf->dcf_lstate = clock.flags;
/*
* up up and away (hopefully ...)
*/
nmp = (mblk_t *)NULL;
if (canput(dcf->dcf_queue->q_next) && (nmp = allocb(sizeof(dcftime_t), BPRI_MED)))
{
bcopy((caddr_t)&dtime, (caddr_t)nmp->b_rptr, sizeof(dcftime_t));
nmp->b_wptr += sizeof(dcftime_t);
putnext(dcf->dcf_queue, nmp);
}
else
if (nmp) freemsg(nmp);
}