1132451Sroberto<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 2132451Sroberto 3132451Sroberto<html> 4132451Sroberto 5182007Sroberto <head> 6182007Sroberto <meta http-equiv="content-type" content="text/html;charset=iso-8859-1"> 7182007Sroberto <title>Making PARSE Clocks</title> 8182007Sroberto <link href="scripts/style.css" type="text/css" rel="stylesheet"> 9182007Sroberto </head> 10132451Sroberto 11182007Sroberto <body> 12182007Sroberto <h3>How to build new PARSE clocks</h3> 13182007Sroberto <p>Here is an attempt to sketch out what you need to do in order to add another clock to the parse driver: Currently the implementation is being cleaned up - so not all information in here is completely correct. Refer to the included code where in doubt.</p> 14182007Sroberto <p>Prerequisites:</p> 15182007Sroberto <ul> 16182007Sroberto <li>Does the system you want the clock connect to have the include files termio.h or termios.h ? (You need that for the parse driver) 17182007Sroberto </ul> 18182007Sroberto <p>What to do:</p> 19182007Sroberto <p>Make a conversion module (libparse/clk_*.c)</p> 20182007Sroberto <ol> 21182007Sroberto <li>What ist the time code format ? 22182007Sroberto <ul> 23182007Sroberto <li>find year, month, day, hour, minute, second, status (synchronised or not), possibly time zone information (you need to give the offset to UTC) You will have to convert the data from a string into a struct clocktime: 24182007Sroberto <pre> 25132451Sroberto struct clocktime /* clock time broken up from time code */ 26132451Sroberto { 27132451Sroberto long day; 28132451Sroberto long month; 29132451Sroberto long year; 30132451Sroberto long hour; 31132451Sroberto long minute; 32132451Sroberto long second; 33132451Sroberto long usecond; 34132451Sroberto long utcoffset; /* in seconds */ 35132451Sroberto time_t utcoffset; /* true utc time instead of date/time */ 36132451Sroberto long flags; /* current clock status */ 37132451Sroberto }; 38132451Sroberto</pre> 39182007Sroberto <p>Conversion is usually simple and straight forward. For the flags following values can be OR'ed together:</p> 40182007Sroberto <pre> 41132451Sroberto PARSEB_ANNOUNCE switch time zone warning (informational only) 42132451Sroberto PARSEB_POWERUP no synchronisation - clock confused (must set then) 43132451Sroberto PARSEB_NOSYNC timecode currently not confirmed (must set then) 44132451Sroberto usually on reception error when there is still a 45132451Sroberto chance the the generated time is still ok. 46132451Sroberto 47132451Sroberto PARSEB_DST DST in effect (informational only) 48132451Sroberto PARSEB_UTC timecode contains UTC time (informational only) 49132451Sroberto PARSEB_LEAPADD LEAP addition warning (prior to leap happening - must set when imminent) 50132451Sroberto also used for time code that do not encode the 51132451Sroberto direction (as this is currently the default). 52132451Sroberto PARSEB_LEAPDEL LEAP deletion warning (prior to leap happening - must set when imminent) 53132451Sroberto PARSEB_ALTERNATE backup transmitter (informational only) 54132451Sroberto PARSEB_POSITION geographic position available (informational only) 55132451Sroberto PARSEB_LEAPSECOND actual leap second (this time code is the leap 56132451Sroberto second - informational only) 57132451Sroberto</pre> 58182007Sroberto <p>These are feature flags denoting items that are supported by the clock:</p> 59182007Sroberto <pre> 60132451Sroberto PARSEB_S_LEAP supports LEAP - might set PARSEB_LEAP 61132451Sroberto PARSEB_S_ANTENNA supports ANTENNA - might set PARSEB_ALTERNATE 62132451Sroberto PARSEB_S_PPS supports PPS time stamping 63132451Sroberto PARSEB_S_POSITION supports position information (GPS) 64132451Sroberto </pre> 65182007Sroberto <p>If the utctime field is non zero this value will be take as time code value. This allows for conversion routines that already have the utc time value. The utctime field gives the seconds since Jan 1st 1970, 0:00:00. The useconds field gives the respective usec value. The fields for date and time (down to second resolution) will be ignored.</p> 66182007Sroberto <p>Conversion is done in the cvt_* routine in parse/clk_*.c files. look in them for examples. The basic structure is:</p> 67182007Sroberto <pre> 68132451Sroberto struct clockformat <yourclock>_format = { 69132451Sroberto lots of fields for you to fill out (see below) 70132451Sroberto }; 71132451Sroberto 72132451Sroberto static cvt_<yourclock>() 73132451Sroberto ... 74132451Sroberto { 75132451Sroberto if (<I do not recognize my time code>) { 76132451Sroberto return CVT_NONE; 77132451Sroberto } else { 78132451Sroberto if (<conversion into clockformat is ok>) { 79132451Sroberto <set all necessary flags>; 80132451Sroberto return CVT_OK; 81132451Sroberto } else { 82132451Sroberto return CVT_FAIL|CVT_BADFMT; 83132451Sroberto } 84132451Sroberto } 85132451Sroberto</pre> 86182007Sroberto <p>The struct clockformat is the interface to the rest of the parse driver - it holds all information necessary for finding the clock message and doing the appropriate time stamping.</p> 87182007Sroberto <pre> 88132451Srobertostruct clockformat 89132451Sroberto{ 90132451Sroberto u_long (*input)(); 91132451Sroberto /* input routine - your routine - cvt_<yourclock> */ 92132451Sroberto u_long (*convert)(); 93132451Sroberto /* conversion routine - your routine - cvt_<yourclock> */ 94132451Sroberto /* routine for handling RS232 sync events (time stamps) - usually sync_simple */ 95132451Sroberto u_long (*syncpps)(); 96132451Sroberto /* PPS input routine - usually pps_one */ 97132451Sroberto void *data; 98132451Sroberto /* local parameters - any parameters/data/configuration info your conversion 99132451Sroberto routine might need */ 100132451Sroberto char *name; 101132451Sroberto /* clock format name - Name of the time code */ 102132451Sroberto unsigned short length; 103132451Sroberto /* maximum length of data packet for your clock format */ 104132451Sroberto u_long flags; 105132451Sroberto /* information for the parser what to look for */ 106132451Sroberto}; 107132451Sroberto</pre> 108182007Sroberto <p>The above should have given you some hints on how to build a clk_*.c file with the time code conversion. See the examples and pick a clock closest to yours and tweak the code to match your clock.</p> 109182007Sroberto <p>In order to make your clk_*.c file usable a reference to the clockformat structure must be put into parse_conf.c.</p> 110182007Sroberto </ul> 111182007Sroberto <li>TTY setup and initialisation/configuration will be done in ntpd/refclock_parse.c. 112182007Sroberto <ul> 113182007Sroberto <li>Find out the exact tty settings for your clock (baud rate, parity, stop bits, character size, ...) and note them in terms of termio*.h c_cflag macros. 114182007Sroberto <li>in ntpd/refclock_parse.c fill out a new the struct clockinfo element (that allocates a new "IP" address - see comments) (see all the other clocks for example) 115182007Sroberto <pre> 116132451Sroberto struct clockinfo 117132451Sroberto { 118132451Sroberto u_long cl_flags; /* operation flags (io modes) */ 119132451Sroberto PARSE_F_PPSPPS use loopfilter PPS code (CIOGETEV) 120132451Sroberto PARSE_F_PPSONSECOND PPS pulses are on second 121132451Sroberto usually flags stay 0 as they are used only for special setups 122132451Sroberto 123132451Sroberto void (*cl_poll)(); /* active poll routine */ 124132451Sroberto The routine to call when the clock needs data sent to it in order to 125132451Sroberto get a time code from the clock (e.g. Trimble clock) 126132451Sroberto 127132451Sroberto int (*cl_init)(); /* active poll init routine */ 128132451Sroberto The routine to call for very special initializations. 129132451Sroberto 130132451Sroberto void (*cl_event)(); /* special event handling (e.g. reset clock) */ 131132451Sroberto What to do, when an event happens - used to re-initialize clocks on timeout. 132132451Sroberto 133132451Sroberto void (*cl_end)(); /* active poll end routine */ 134132451Sroberto The routine to call to undo any special initialisation (free memory/timers) 135132451Sroberto 136132451Sroberto void *cl_data; /* local data area for "poll" mechanism */ 137132451Sroberto local data for polling routines 138132451Sroberto 139132451Sroberto u_fp cl_rootdelay; /* rootdelay */ 140132451Sroberto NTP rootdelay estimate (usually 0) 141132451Sroberto 142132451Sroberto u_long cl_basedelay; /* current offset - unsigned l_fp 143132451Sroberto fractional part (fraction) by 144132451Sroberto which the RS232 time code is 145132451Sroberto delayed from the actual time. */ 146132451Sroberto 147132451Sroberto u_long cl_ppsdelay; /* current PPS offset - unsigned l_fp fractional 148132451Sroberto time (fraction) by which the PPS time stamp is delayed (usually 0) 149132451Sroberto part */ 150132451Sroberto 151132451Sroberto char *cl_id; /* ID code (usually "DCF") */ 152132451Sroberto Refclock id - (max 4 chars) 153132451Sroberto 154132451Sroberto char *cl_description; /* device name */ 155132451Sroberto Name of this device. 156132451Sroberto 157132451Sroberto char *cl_format; /* fixed format */ 158132451Sroberto If the data format cann not ne detected automatically this is the name 159132451Sroberto as in clk_*.c clockformat. 160132451Sroberto 161132451Sroberto u_char cl_type; /* clock type (ntp control) */ 162132451Sroberto Type if clock as in clock status word (ntp control messages) - usually 0 163132451Sroberto 164132451Sroberto u_long cl_maxunsync; /* time to trust oscillator after losing synch 165132451Sroberto */ 166132451Sroberto seconds a clock can be trusted after losing synchronisation. 167132451Sroberto 168132451Sroberto u_long cl_speed; /* terminal input & output baudrate */ 169132451Sroberto u_long cl_cflag; /* terminal io flags */ 170132451Sroberto u_long cl_iflag; /* terminal io flags */ 171132451Sroberto u_long cl_oflag; /* terminal io flags */ 172132451Sroberto u_long cl_lflag; /* terminal io flags */ 173132451Sroberto termio*.h tty modes. 174132451Sroberto 175132451Sroberto u_long cl_samples; /* samples for median filter */ 176132451Sroberto u_long cl_keep; /* samples for median filter to keep */ 177132451Sroberto median filter parameters - smoothing and rejection of bad samples 178132451Sroberto } clockinfo[] = { 179132451Sroberto ...,<other clocks>,... 180132451Sroberto { < your parameters> }, 181132451Sroberto }; 182132451Sroberto 183132451Sroberto</pre> 184182007Sroberto </ul> 185182007Sroberto </ol> 186182007Sroberto <p>Well, this is very sketchy, i know. But I hope it helps a little bit. The best way is to look which clock comes closest to your and tweak that code.</p> 187182007Sroberto <p>Two sorts of clocks are used with parse. Clocks that automatically send their time code (once a second) do not need entries in the poll routines because they send the data all the time. The second sort are the clocks that need a command sent to them in order to reply with a time code (like the Trimble clock).</p> 188182007Sroberto <p>For questions: <a href="mailto:%20kardel <AT> acm.org">kardel 189182007Sroberto <AT> 190182007Sroberto acm.org</a>.</p> 191182007Sroberto <p>Please include an exact description on how your clock works. (initialisation, TTY modes, strings to be sent to it, responses received from the clock).</p> 192182007Sroberto <hr> 193182007Sroberto <script type="text/javascript" language="javascript" src="scripts/footer.txt"></script> 194182007Sroberto </body> 195132451Sroberto 196182007Sroberto <body></body> 197132451Sroberto 198182007Sroberto</html>