README.new_clocks revision 7c478bd95313f5f23a4c958a745db2134aa03244
0N/A ident "%Z%%M% %I% %E% SMI"
2362N/A
0N/AHere is an attempt to sketch out what you need to do in order to
0N/Aadd another clock to the parse driver:
0N/A
0N/APrerequisites:
2362N/A- Does the system you want the clock connect to have
0N/A termio.h or termios.h ? (You need that for the parse driver)
2362N/A
0N/AWhat to do:
0N/A
0N/AMake a conversion module (parse/clk_*.c)
0N/A
0N/A- What ist the time code format ?
0N/A - find year, month, day, hour, minute, second, status (synchronised or
0N/A not), possibly time zone information (you need to give the offset to UTC)
0N/A You will have to convert the data from a string into a struct clocktime:
0N/A struct clocktime /* clock time broken up from time code */
0N/A {
0N/A long day;
2362N/A long month;
2362N/A long year;
2362N/A long hour;
0N/A long minute;
0N/A long second;
0N/A long usecond;
0N/A long utcoffset; /* in seconds */
0N/A time_t utcoffset; /* true utc time instead of date/time */
0N/A long flags; /* current clock status */
0N/A };
0N/A
0N/A Conversion is usually simple and straight forward. For the flags following
0N/A values can be OR'ed together:
0N/A
0N/A PARSEB_ANNOUNCE switch time zone warning (informational only)
0N/A PARSEB_POWERUP no synchronisation - clock confused (must set then)
0N/A PARSEB_NOSYNC timecode currently not confirmed (must set then)
0N/A usually on reception error when there is still a
0N/A chance the the generated time is still ok.
0N/A
0N/A PARSEB_DST DST in effect (informational only)
0N/A PARSEB_UTC timecode contains UTC time (informational only)
0N/A PARSEB_LEAPADD LEAP addition warning (prior to leap happening - must set when imminent)
1505N/A also used for time code that do not encode the
1505N/A direction (as this is currently the default).
1505N/A PARSEB_LEAPDEL LEAP deletion warning (prior to leap happening - must set when imminent)
1505N/A PARSEB_ALTERNATE backup transmitter (informational only)
1505N/A PARSEB_POSITION geographic position available (informational only)
1505N/A PARSEB_LEAPSECOND actual leap second (this time code is the leap
1505N/A second - informational only)
1505N/A
1505N/A These are feature flags denoting items that are supported by the clock:
0N/A PARSEB_S_LEAP supports LEAP - might set PARSEB_LEAP
0N/A PARSEB_S_ANTENNA supports ANTENNA - might set PARSEB_ALTERNATE
0N/A PARSEB_S_PPS supports PPS time stamping
0N/A PARSEB_S_POSITION supports position information (GPS)
0N/A
0N/A If the utctime field is non zero this value will be take as
0N/A time code value. This allows for conversion routines that
0N/A already have the utc time value. The utctime field gives the seconds
0N/A since Jan 1st 1970, 0:00:00. The useconds field gives the respective
0N/A usec value. The fields for date and time (down to second resolution)
0N/A will be ignored.
0N/A
0N/A Conversion is done in the cvt_* routine in parse/clk_*.c files. look in
0N/A them for examples. The basic structure is:
0N/A
0N/A struct clockformat <yourclock>_format = {
0N/A lots of fields for you to fill out (see below)
0N/A };
0N/A
0N/A static cvt_<yourclock>()
0N/A ...
0N/A {
0N/A if (<I do not recognize my time code>) {
0N/A return CVT_NONE;
0N/A } else {
0N/A if (<conversion into clockformat is ok>) {
0N/A <set all necessary flags>;
0N/A return CVT_OK;
0N/A } else {
0N/A return CVT_FAIL|CVT_BADFMT;
0N/A }
0N/A }
0N/A
0N/A The struct clockformat is the interface to the rest of the parse
0N/A driver - it holds all information necessary for finding the
0N/A clock message and doing the appropriate time stamping.
0N/A
0N/Astruct clockformat
0N/A{
0N/A u_long (*convert)();
0N/A /* conversion routine - your routine - cvt_<yourclock> */
0N/A void (*syncevt)();
0N/A /* routine for handling RS232 sync events (time stamps) - usually sync_simple */
0N/A u_long (*syncpps)();
0N/A /* PPS input routine - usually pps_simple */
0N/A u_long (*synth)();
0N/A /* time code synthesizer - usually not used - (long (*)())0 */
0N/A void *data;
0N/A /* local parameters - any parameters/data/configuration info your conversion
0N/A routine might need */
0N/A char *name;
0N/A /* clock format name - Name of the time code */
0N/A unsigned short length;
0N/A /* maximum length of data packet for your clock format */
0N/A u_long flags;
0N/A /* information for the parser what to look for */
0N/A struct timeval timeout;
0N/A /* buffer restart after timeout (us) - some clocks preceede new data by
0N/A a longer period of silence - unsually not used */
0N/A unsigned char startsym;
0N/A /* start symbol - character at the beginning of the clock data */
0N/A unsigned char endsym;
0N/A /* end symbol - character at the end of the clock data */
0N/A unsigned char syncsym;
0N/A /* sync symbol - character that is "on time" - where the time stamp should be taken */
0N/A};
0N/A
0N/A The flags:
0N/A F_START use startsym to find the beginning of the clock data
0N/A F_END use endsym to find the end of the clock data
0N/A SYNC_TIMEOUT packet restart after timeout in timeout field
0N/A SYNC_START packet start is sync event (time stamp at paket start)
0N/A SYNC_END packet end is sync event (time stamp at paket end)
0N/A SYNC_CHAR special character (syncsym) is sync event
0N/A SYNC_ONE PPS synchronize on 'ONE' transition
0N/A SYNC_ZERO PPS synchronize on 'ZERO' transition
0N/A SYNC_SYNTHESIZE generate intermediate time stamps (very special case!)
0N/A CVT_FIXEDONLY convert only in fixed configuration - (data format not
0N/A suitable for auto-configuration)
0N/A
0N/A
0N/A The above should have given you some hints on how to build a clk_*.c
0N/A file with the time code conversion. See the examples and pick a clock
0N/A closest to yours and tweak the code to match your clock.
0N/A
0N/A In order to make your clk_*.c file usable a reference to the clockformat
0N/A structure must be put into parse_conf.c.
0N/A
0N/ATTY setup and initialisation/configuration will be done in
0N/Axntpd/refclock_parse.c
0N/A
0N/A- Find out the exact tty settings for your clock (baud rate, parity,
0N/A stop bits, character size, ...) and note them in terms of
0N/A termio*.h c_cflag macros.
0N/A
0N/A- in xntpd/refclock_parse.c fill out a new the struct clockinfo element
0N/A (that allocates a new "IP" address - see comments)
0N/A (see all the other clocks for example)
0N/A struct clockinfo
0N/A {
0N/A u_long cl_flags; /* operation flags (io modes) */
0N/A PARSE_F_NOPOLLONLY always do async io - read whenever input comes
0N/A PARSE_F_POLLONLY never do async io - only read when expecting data
0N/A PARSE_F_PPSPPS use loopfilter PPS code (CIOGETEV)
0N/A PARSE_F_PPSONSECOND PPS pulses are on second
0N/A usually flags stay 0 as they are used only for special setups
0N/A
0N/A void (*cl_poll)(); /* active poll routine */
0N/A The routine to call when the clock needs data sent to it in order to
0N/A get a time code from the clock (e.g. Trimble clock)
0N/A int (*cl_init)(); /* active poll init routine */
0N/A The routine to call for very special initializations.
0N/A void (*cl_end)(); /* active poll end routine */
0N/A The routine to call to undo any special initialisation (free memory/timers)
0N/A void *cl_data; /* local data area for "poll" mechanism */
0N/A local data for polling routines
0N/A u_fp cl_rootdelay; /* rootdelay */
0N/A NTP rottdelay estimate (usually 0)
0N/A u_long cl_basedelay; /* current offset - unsigned l_fp fractional par
0N/A time (fraction) by which the RS232 time code is delayed from the actual time.
0N/A t */
0N/A u_long cl_ppsdelay; /* current PPS offset - unsigned l_fp fractional
0N/A time (fraction) by which the PPS time stamp is delayed (usually 0)
0N/A part */
0N/A char *cl_id; /* ID code (usually "DCF") */
0N/A Refclock id - (max 4 chars)
0N/A char *cl_description; /* device name */
0N/A Name of this device.
0N/A char *cl_format; /* fixed format */
0N/A If the data format cann not ne detected automatically this is the name
0N/A as in clk_*.c clockformat.
0N/A u_char cl_type; /* clock type (ntp control) */
0N/A Type if clock as in clock status word (ntp control messages) - usually 0
0N/A u_long cl_maxunsync; /* time to trust oscillator after loosing synch
0N/A */
0N/A seconds a clock can be trusted after loosing synchronisation.
0N/A
0N/A u_long cl_cflag; /* terminal io flags */
0N/A u_long cl_iflag; /* terminal io flags */
0N/A u_long cl_oflag; /* terminal io flags */
0N/A u_long cl_lflag; /* terminal io flags */
0N/A termio*.h tty modes.
0N/A } clockinfo[] = {
0N/A ...,<other clocks>,...
0N/A { < your parameters> },
1505N/A };
1505N/A
1505N/A
1505N/AWell, this is very sketchy, i know. But I hope it helps a little bit.
1505N/AThe best way is to look which clock comes closest to your and tweak that
1505N/Acode.
1505N/ATwo sorts of clocks are used with parse. Clocks that automatically send
1505N/Atheir time code (once a second) do not need entries in the poll routines because
1505N/Athey send the data all the time. The second sort are the clocks that need a
1505N/Acommand sent to them in order to reply with a time code (like the Trimble
0N/Aclock).
0N/A
0N/AFor questions: kardel@informatik.uni-erlangen.de. Please include
0N/Aan exact description on how your clock works. (initialisation,
0N/ATTY modes, strings to be sent to it, responses received from the clock).
0N/A
0N/AFrank Kardel
0N/A