19c2daa00SOllivier Robert<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 29c2daa00SOllivier Robert 39c2daa00SOllivier Robert<html> 49c2daa00SOllivier Robert 59c2daa00SOllivier Robert <head> 6ea906c41SOllivier Robert <meta http-equiv="content-type" content="text/html;charset=iso-8859-1"> 79c2daa00SOllivier Robert <title>Making PARSE Clocks</title> 89c2daa00SOllivier Robert <link href="scripts/style.css" type="text/css" rel="stylesheet"> 99c2daa00SOllivier Robert </head> 109c2daa00SOllivier Robert 119c2daa00SOllivier Robert <body> 129c2daa00SOllivier Robert <h3>How to build new PARSE clocks</h3> 139c2daa00SOllivier Robert <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> 149c2daa00SOllivier Robert <p>Prerequisites:</p> 159c2daa00SOllivier Robert <ul> 169c2daa00SOllivier Robert <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) 179c2daa00SOllivier Robert </ul> 189c2daa00SOllivier Robert <p>What to do:</p> 199c2daa00SOllivier Robert <p>Make a conversion module (libparse/clk_*.c)</p> 209c2daa00SOllivier Robert <ol> 219c2daa00SOllivier Robert <li>What ist the time code format ? 229c2daa00SOllivier Robert <ul> 239c2daa00SOllivier Robert <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: 249c2daa00SOllivier Robert <pre> 259c2daa00SOllivier Robert struct clocktime /* clock time broken up from time code */ 269c2daa00SOllivier Robert { 279c2daa00SOllivier Robert long day; 289c2daa00SOllivier Robert long month; 299c2daa00SOllivier Robert long year; 309c2daa00SOllivier Robert long hour; 319c2daa00SOllivier Robert long minute; 329c2daa00SOllivier Robert long second; 339c2daa00SOllivier Robert long usecond; 349c2daa00SOllivier Robert long utcoffset; /* in seconds */ 359c2daa00SOllivier Robert time_t utcoffset; /* true utc time instead of date/time */ 369c2daa00SOllivier Robert long flags; /* current clock status */ 379c2daa00SOllivier Robert }; 389c2daa00SOllivier Robert</pre> 399c2daa00SOllivier Robert <p>Conversion is usually simple and straight forward. For the flags following values can be OR'ed together:</p> 409c2daa00SOllivier Robert <pre> 419c2daa00SOllivier Robert PARSEB_ANNOUNCE switch time zone warning (informational only) 429c2daa00SOllivier Robert PARSEB_POWERUP no synchronisation - clock confused (must set then) 439c2daa00SOllivier Robert PARSEB_NOSYNC timecode currently not confirmed (must set then) 449c2daa00SOllivier Robert usually on reception error when there is still a 459c2daa00SOllivier Robert chance the the generated time is still ok. 469c2daa00SOllivier Robert 479c2daa00SOllivier Robert PARSEB_DST DST in effect (informational only) 489c2daa00SOllivier Robert PARSEB_UTC timecode contains UTC time (informational only) 499c2daa00SOllivier Robert PARSEB_LEAPADD LEAP addition warning (prior to leap happening - must set when imminent) 509c2daa00SOllivier Robert also used for time code that do not encode the 519c2daa00SOllivier Robert direction (as this is currently the default). 529c2daa00SOllivier Robert PARSEB_LEAPDEL LEAP deletion warning (prior to leap happening - must set when imminent) 539c2daa00SOllivier Robert PARSEB_ALTERNATE backup transmitter (informational only) 549c2daa00SOllivier Robert PARSEB_POSITION geographic position available (informational only) 559c2daa00SOllivier Robert PARSEB_LEAPSECOND actual leap second (this time code is the leap 569c2daa00SOllivier Robert second - informational only) 579c2daa00SOllivier Robert</pre> 589c2daa00SOllivier Robert <p>These are feature flags denoting items that are supported by the clock:</p> 599c2daa00SOllivier Robert <pre> 609c2daa00SOllivier Robert PARSEB_S_LEAP supports LEAP - might set PARSEB_LEAP 619c2daa00SOllivier Robert PARSEB_S_ANTENNA supports ANTENNA - might set PARSEB_ALTERNATE 629c2daa00SOllivier Robert PARSEB_S_PPS supports PPS time stamping 639c2daa00SOllivier Robert PARSEB_S_POSITION supports position information (GPS) 649c2daa00SOllivier Robert </pre> 659c2daa00SOllivier Robert <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> 669c2daa00SOllivier Robert <p>Conversion is done in the cvt_* routine in parse/clk_*.c files. look in them for examples. The basic structure is:</p> 679c2daa00SOllivier Robert <pre> 689c2daa00SOllivier Robert struct clockformat <yourclock>_format = { 699c2daa00SOllivier Robert lots of fields for you to fill out (see below) 709c2daa00SOllivier Robert }; 719c2daa00SOllivier Robert 729c2daa00SOllivier Robert static cvt_<yourclock>() 739c2daa00SOllivier Robert ... 749c2daa00SOllivier Robert { 759c2daa00SOllivier Robert if (<I do not recognize my time code>) { 769c2daa00SOllivier Robert return CVT_NONE; 779c2daa00SOllivier Robert } else { 789c2daa00SOllivier Robert if (<conversion into clockformat is ok>) { 799c2daa00SOllivier Robert <set all necessary flags>; 809c2daa00SOllivier Robert return CVT_OK; 819c2daa00SOllivier Robert } else { 829c2daa00SOllivier Robert return CVT_FAIL|CVT_BADFMT; 839c2daa00SOllivier Robert } 849c2daa00SOllivier Robert } 859c2daa00SOllivier Robert</pre> 869c2daa00SOllivier Robert <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> 879c2daa00SOllivier Robert <pre> 889c2daa00SOllivier Robertstruct clockformat 899c2daa00SOllivier Robert{ 909c2daa00SOllivier Robert u_long (*input)(); 919c2daa00SOllivier Robert /* input routine - your routine - cvt_<yourclock> */ 929c2daa00SOllivier Robert u_long (*convert)(); 939c2daa00SOllivier Robert /* conversion routine - your routine - cvt_<yourclock> */ 949c2daa00SOllivier Robert /* routine for handling RS232 sync events (time stamps) - usually sync_simple */ 959c2daa00SOllivier Robert u_long (*syncpps)(); 969c2daa00SOllivier Robert /* PPS input routine - usually pps_one */ 979c2daa00SOllivier Robert void *data; 989c2daa00SOllivier Robert /* local parameters - any parameters/data/configuration info your conversion 999c2daa00SOllivier Robert routine might need */ 1009c2daa00SOllivier Robert char *name; 1019c2daa00SOllivier Robert /* clock format name - Name of the time code */ 1029c2daa00SOllivier Robert unsigned short length; 1039c2daa00SOllivier Robert /* maximum length of data packet for your clock format */ 1049c2daa00SOllivier Robert u_long flags; 1059c2daa00SOllivier Robert /* information for the parser what to look for */ 1069c2daa00SOllivier Robert}; 1079c2daa00SOllivier Robert</pre> 1089c2daa00SOllivier Robert <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> 1099c2daa00SOllivier Robert <p>In order to make your clk_*.c file usable a reference to the clockformat structure must be put into parse_conf.c.</p> 1109c2daa00SOllivier Robert </ul> 1119c2daa00SOllivier Robert <li>TTY setup and initialisation/configuration will be done in ntpd/refclock_parse.c. 1129c2daa00SOllivier Robert <ul> 1139c2daa00SOllivier Robert <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. 1149c2daa00SOllivier Robert <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) 1159c2daa00SOllivier Robert <pre> 1169c2daa00SOllivier Robert struct clockinfo 1179c2daa00SOllivier Robert { 1189c2daa00SOllivier Robert u_long cl_flags; /* operation flags (io modes) */ 1199c2daa00SOllivier Robert PARSE_F_PPSPPS use loopfilter PPS code (CIOGETEV) 1209c2daa00SOllivier Robert PARSE_F_PPSONSECOND PPS pulses are on second 1219c2daa00SOllivier Robert usually flags stay 0 as they are used only for special setups 1229c2daa00SOllivier Robert 1239c2daa00SOllivier Robert void (*cl_poll)(); /* active poll routine */ 1249c2daa00SOllivier Robert The routine to call when the clock needs data sent to it in order to 1259c2daa00SOllivier Robert get a time code from the clock (e.g. Trimble clock) 1269c2daa00SOllivier Robert 1279c2daa00SOllivier Robert int (*cl_init)(); /* active poll init routine */ 1289c2daa00SOllivier Robert The routine to call for very special initializations. 1299c2daa00SOllivier Robert 1309c2daa00SOllivier Robert void (*cl_event)(); /* special event handling (e.g. reset clock) */ 1319c2daa00SOllivier Robert What to do, when an event happens - used to re-initialize clocks on timeout. 1329c2daa00SOllivier Robert 1339c2daa00SOllivier Robert void (*cl_end)(); /* active poll end routine */ 1349c2daa00SOllivier Robert The routine to call to undo any special initialisation (free memory/timers) 1359c2daa00SOllivier Robert 1369c2daa00SOllivier Robert void *cl_data; /* local data area for "poll" mechanism */ 1379c2daa00SOllivier Robert local data for polling routines 1389c2daa00SOllivier Robert 1399c2daa00SOllivier Robert u_fp cl_rootdelay; /* rootdelay */ 1409c2daa00SOllivier Robert NTP rootdelay estimate (usually 0) 1419c2daa00SOllivier Robert 1429c2daa00SOllivier Robert u_long cl_basedelay; /* current offset - unsigned l_fp 1439c2daa00SOllivier Robert fractional part (fraction) by 1449c2daa00SOllivier Robert which the RS232 time code is 1459c2daa00SOllivier Robert delayed from the actual time. */ 1469c2daa00SOllivier Robert 1479c2daa00SOllivier Robert u_long cl_ppsdelay; /* current PPS offset - unsigned l_fp fractional 1489c2daa00SOllivier Robert time (fraction) by which the PPS time stamp is delayed (usually 0) 1499c2daa00SOllivier Robert part */ 1509c2daa00SOllivier Robert 1519c2daa00SOllivier Robert char *cl_id; /* ID code (usually "DCF") */ 1529c2daa00SOllivier Robert Refclock id - (max 4 chars) 1539c2daa00SOllivier Robert 1549c2daa00SOllivier Robert char *cl_description; /* device name */ 1559c2daa00SOllivier Robert Name of this device. 1569c2daa00SOllivier Robert 1579c2daa00SOllivier Robert char *cl_format; /* fixed format */ 1589c2daa00SOllivier Robert If the data format cann not ne detected automatically this is the name 1599c2daa00SOllivier Robert as in clk_*.c clockformat. 1609c2daa00SOllivier Robert 1619c2daa00SOllivier Robert u_char cl_type; /* clock type (ntp control) */ 1629c2daa00SOllivier Robert Type if clock as in clock status word (ntp control messages) - usually 0 1639c2daa00SOllivier Robert 1649c2daa00SOllivier Robert u_long cl_maxunsync; /* time to trust oscillator after losing synch 1659c2daa00SOllivier Robert */ 1669c2daa00SOllivier Robert seconds a clock can be trusted after losing synchronisation. 1679c2daa00SOllivier Robert 1689c2daa00SOllivier Robert u_long cl_speed; /* terminal input & output baudrate */ 1699c2daa00SOllivier Robert u_long cl_cflag; /* terminal io flags */ 1709c2daa00SOllivier Robert u_long cl_iflag; /* terminal io flags */ 1719c2daa00SOllivier Robert u_long cl_oflag; /* terminal io flags */ 1729c2daa00SOllivier Robert u_long cl_lflag; /* terminal io flags */ 1739c2daa00SOllivier Robert termio*.h tty modes. 1749c2daa00SOllivier Robert 1759c2daa00SOllivier Robert u_long cl_samples; /* samples for median filter */ 1769c2daa00SOllivier Robert u_long cl_keep; /* samples for median filter to keep */ 1779c2daa00SOllivier Robert median filter parameters - smoothing and rejection of bad samples 1789c2daa00SOllivier Robert } clockinfo[] = { 1799c2daa00SOllivier Robert ...,<other clocks>,... 1809c2daa00SOllivier Robert { < your parameters> }, 1819c2daa00SOllivier Robert }; 1829c2daa00SOllivier Robert 1839c2daa00SOllivier Robert</pre> 1849c2daa00SOllivier Robert </ul> 1859c2daa00SOllivier Robert </ol> 1869c2daa00SOllivier Robert <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> 1879c2daa00SOllivier Robert <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> 188ea906c41SOllivier Robert <p>For questions: <a href="mailto:%20kardel <AT> acm.org">kardel 189ea906c41SOllivier Robert <AT> 190ea906c41SOllivier Robert acm.org</a>.</p> 1919c2daa00SOllivier Robert <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> 1929c2daa00SOllivier Robert <hr> 1939c2daa00SOllivier Robert <script type="text/javascript" language="javascript" src="scripts/footer.txt"></script> 1949c2daa00SOllivier Robert </body> 1959c2daa00SOllivier Robert 1969c2daa00SOllivier Robert <body></body> 1979c2daa00SOllivier Robert 1989c2daa00SOllivier Robert</html>