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