1 1.24 christos /* $NetBSD: refclock_parse.c,v 1.25 2024/08/18 20:47:18 christos Exp $ */ 2 1.1 kardel 3 1.1 kardel /* 4 1.1 kardel * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 5 1.1 kardel * 6 1.1 kardel * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 7 1.1 kardel * 8 1.1 kardel * generic reference clock driver for several DCF/GPS/MSF/... receivers 9 1.1 kardel * 10 1.1 kardel * PPS notes: 11 1.1 kardel * On systems that support PPSAPI (RFC2783) PPSAPI is the 12 1.1 kardel * preferred interface. 13 1.1 kardel * 14 1.1 kardel * Optionally make use of a STREAMS module for input processing where 15 1.1 kardel * available and configured. This STREAMS module reduces the time 16 1.1 kardel * stamp latency for serial and PPS events. 17 1.1 kardel * Currently the STREAMS module is only available for Suns running 18 1.1 kardel * SunOS 4.x and SunOS5.x. 19 1.1 kardel * 20 1.16 christos * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org> 21 1.15 christos * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany 22 1.1 kardel * 23 1.1 kardel * Redistribution and use in source and binary forms, with or without 24 1.1 kardel * modification, are permitted provided that the following conditions 25 1.1 kardel * are met: 26 1.1 kardel * 1. Redistributions of source code must retain the above copyright 27 1.1 kardel * notice, this list of conditions and the following disclaimer. 28 1.1 kardel * 2. Redistributions in binary form must reproduce the above copyright 29 1.1 kardel * notice, this list of conditions and the following disclaimer in the 30 1.1 kardel * documentation and/or other materials provided with the distribution. 31 1.1 kardel * 3. Neither the name of the author nor the names of its contributors 32 1.1 kardel * may be used to endorse or promote products derived from this software 33 1.1 kardel * without specific prior written permission. 34 1.1 kardel * 35 1.1 kardel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 36 1.1 kardel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 1.1 kardel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 1.1 kardel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 39 1.1 kardel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 40 1.1 kardel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 41 1.1 kardel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 42 1.1 kardel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 43 1.1 kardel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 44 1.1 kardel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 45 1.1 kardel * SUCH DAMAGE. 46 1.1 kardel * 47 1.1 kardel */ 48 1.1 kardel 49 1.1 kardel #ifdef HAVE_CONFIG_H 50 1.1 kardel # include "config.h" 51 1.1 kardel #endif 52 1.1 kardel 53 1.10 christos #include "ntp_types.h" 54 1.10 christos 55 1.1 kardel #if defined(REFCLOCK) && defined(CLOCK_PARSE) 56 1.1 kardel 57 1.1 kardel /* 58 1.1 kardel * This driver currently provides the support for 59 1.15 christos * - Meinberg receiver DCF77 PZF535 (TCXO version) (DCF) 60 1.15 christos * - Meinberg receiver DCF77 PZF535 (OCXO version) (DCF) 61 1.15 christos * - Meinberg receiver DCF77 PZF509 (DCF) 62 1.1 kardel * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) 63 1.1 kardel * - IGEL CLOCK (DCF) 64 1.1 kardel * - ELV DCF7000 (DCF) 65 1.1 kardel * - Schmid clock (DCF) 66 1.1 kardel * - Conrad DCF77 receiver module (DCF) 67 1.1 kardel * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 68 1.15 christos * - WHARTON 400A Series clock (DCF) 69 1.1 kardel * 70 1.15 christos * - Meinberg GPS receivers (GPS) 71 1.1 kardel * - Trimble (TSIP and TAIP protocol) (GPS) 72 1.1 kardel * 73 1.1 kardel * - RCC8000 MSF Receiver (MSF) 74 1.15 christos * - VARITEXT clock (MSF) 75 1.1 kardel */ 76 1.1 kardel 77 1.1 kardel /* 78 1.1 kardel * Meinberg receivers are usually connected via a 79 1.15 christos * 9600/7E1 or 19200/8N1 serial line. 80 1.1 kardel * 81 1.1 kardel * The Meinberg GPS receivers also have a special NTP time stamp 82 1.1 kardel * format. The firmware release is Uni-Erlangen. 83 1.1 kardel * 84 1.1 kardel * Meinberg generic receiver setup: 85 1.15 christos * output time code every second 86 1.15 christos * Baud rate 9600 7E2S 87 1.1 kardel * 88 1.15 christos * Meinberg GPS receiver setup: 89 1.1 kardel * output time code every second 90 1.1 kardel * Baudrate 19200 8N1 91 1.1 kardel * 92 1.1 kardel * This software supports the standard data formats used 93 1.1 kardel * in Meinberg receivers. 94 1.1 kardel * 95 1.1 kardel * Special software versions are only sensible for the 96 1.15 christos * oldest GPS receiver, GPS16x. For newer receiver types 97 1.15 christos * the output string format can be configured at the device, 98 1.15 christos * and the device name is generally GPSxxx instead of GPS16x. 99 1.1 kardel * 100 1.1 kardel * Meinberg can be reached via: http://www.meinberg.de/ 101 1.1 kardel */ 102 1.1 kardel 103 1.1 kardel #include "ntpd.h" 104 1.1 kardel #include "ntp_refclock.h" 105 1.10 christos #include "timevalops.h" /* includes <sys/time.h> */ 106 1.1 kardel #include "ntp_control.h" 107 1.1 kardel #include "ntp_string.h" 108 1.25 christos #include "ntp_clockdev.h" 109 1.1 kardel 110 1.1 kardel #include <stdio.h> 111 1.1 kardel #include <ctype.h> 112 1.1 kardel #ifndef TM_IN_SYS_TIME 113 1.1 kardel # include <time.h> 114 1.1 kardel #endif 115 1.1 kardel 116 1.1 kardel #ifdef HAVE_UNISTD_H 117 1.1 kardel # include <unistd.h> 118 1.1 kardel #endif 119 1.1 kardel 120 1.1 kardel #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) 121 1.1 kardel # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" 122 1.1 kardel #endif 123 1.1 kardel 124 1.1 kardel #ifdef STREAM 125 1.1 kardel # include <sys/stream.h> 126 1.1 kardel # include <sys/stropts.h> 127 1.1 kardel #endif 128 1.1 kardel 129 1.1 kardel #ifdef HAVE_TERMIOS 130 1.10 christos # include <termios.h> 131 1.1 kardel # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 132 1.1 kardel # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 133 1.1 kardel # undef HAVE_SYSV_TTYS 134 1.1 kardel #endif 135 1.1 kardel 136 1.1 kardel #ifdef HAVE_SYSV_TTYS 137 1.1 kardel # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 138 1.1 kardel # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 139 1.1 kardel #endif 140 1.1 kardel 141 1.1 kardel #ifdef HAVE_BSD_TTYS 142 1.1 kardel /* #error CURRENTLY NO BSD TTY SUPPORT */ 143 1.1 kardel # include "Bletch: BSD TTY not currently supported" 144 1.1 kardel #endif 145 1.1 kardel 146 1.1 kardel #ifdef HAVE_SYS_IOCTL_H 147 1.1 kardel # include <sys/ioctl.h> 148 1.1 kardel #endif 149 1.1 kardel 150 1.1 kardel #ifdef HAVE_PPSAPI 151 1.1 kardel # include "ppsapi_timepps.h" 152 1.1 kardel # include "refclock_atom.h" 153 1.1 kardel #endif 154 1.1 kardel 155 1.1 kardel #ifdef PPS 156 1.1 kardel # ifdef HAVE_SYS_PPSCLOCK_H 157 1.1 kardel # include <sys/ppsclock.h> 158 1.1 kardel # endif 159 1.1 kardel # ifdef HAVE_TIO_SERIAL_STUFF 160 1.1 kardel # include <linux/serial.h> 161 1.1 kardel # endif 162 1.1 kardel #endif 163 1.1 kardel 164 1.15 christos # define BUFFER_SIZE(_BUF, _PTR) ((int)((_BUF) + sizeof(_BUF) - (_PTR))) 165 1.15 christos # define BUFFER_SIZES(_BUF, _PTR, _SZ) ((int)((_BUF) + (_SZ) - (_PTR))) 166 1.1 kardel 167 1.1 kardel /* 168 1.1 kardel * document type of PPS interfacing - copy of ifdef mechanism in local_input() 169 1.1 kardel */ 170 1.15 christos #undef PPS_METHOD 171 1.1 kardel 172 1.1 kardel #ifdef HAVE_PPSAPI 173 1.1 kardel #define PPS_METHOD "PPS API" 174 1.1 kardel #else 175 1.1 kardel #ifdef TIOCDCDTIMESTAMP 176 1.1 kardel #define PPS_METHOD "TIOCDCDTIMESTAMP" 177 1.1 kardel #else /* TIOCDCDTIMESTAMP */ 178 1.1 kardel #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 179 1.1 kardel #ifdef HAVE_CIOGETEV 180 1.1 kardel #define PPS_METHOD "CIOGETEV" 181 1.1 kardel #endif 182 1.1 kardel #ifdef HAVE_TIOCGPPSEV 183 1.1 kardel #define PPS_METHOD "TIOCGPPSEV" 184 1.1 kardel #endif 185 1.1 kardel #endif 186 1.1 kardel #endif /* TIOCDCDTIMESTAMP */ 187 1.1 kardel #endif /* HAVE_PPSAPI */ 188 1.1 kardel 189 1.15 christos /* 190 1.15 christos * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF 191 1.15 christos * then some more parse-specific variables are flagged to be printed with 192 1.15 christos * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF 193 1.15 christos * should be defined as 0. 194 1.15 christos */ 195 1.15 christos #if 0 196 1.15 christos # define COND_DEF DEF // enable this for testing 197 1.15 christos #else 198 1.15 christos # define COND_DEF 0 // enable this by default 199 1.15 christos #endif 200 1.15 christos 201 1.1 kardel #include "ntp_io.h" 202 1.1 kardel #include "ntp_stdlib.h" 203 1.1 kardel 204 1.1 kardel #include "parse.h" 205 1.1 kardel #include "mbg_gps166.h" 206 1.1 kardel #include "trimble.h" 207 1.1 kardel #include "binio.h" 208 1.1 kardel #include "ascii.h" 209 1.1 kardel #include "ieee754io.h" 210 1.1 kardel #include "recvbuff.h" 211 1.1 kardel 212 1.5 kardel static char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST"; 213 1.1 kardel 214 1.1 kardel /**=========================================================================== 215 1.1 kardel ** external interface to ntp mechanism 216 1.1 kardel **/ 217 1.1 kardel 218 1.1 kardel static int parse_start (int, struct peer *); 219 1.1 kardel static void parse_shutdown (int, struct peer *); 220 1.1 kardel static void parse_poll (int, struct peer *); 221 1.10 christos static void parse_control (int, const struct refclockstat *, struct refclockstat *, struct peer *); 222 1.1 kardel 223 1.1 kardel struct refclock refclock_parse = { 224 1.1 kardel parse_start, 225 1.1 kardel parse_shutdown, 226 1.1 kardel parse_poll, 227 1.1 kardel parse_control, 228 1.1 kardel noentry, 229 1.1 kardel noentry, 230 1.1 kardel NOFLAGS 231 1.1 kardel }; 232 1.1 kardel 233 1.1 kardel /* 234 1.1 kardel * Definitions 235 1.1 kardel */ 236 1.1 kardel #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 237 1.1 kardel #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 238 1.1 kardel #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */ 239 1.1 kardel 240 1.1 kardel #undef ABS 241 1.1 kardel #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 242 1.1 kardel 243 1.1 kardel #define PARSE_HARDPPS_DISABLE 0 244 1.1 kardel #define PARSE_HARDPPS_ENABLE 1 245 1.1 kardel 246 1.1 kardel /**=========================================================================== 247 1.1 kardel ** function vector for dynamically binding io handling mechanism 248 1.1 kardel **/ 249 1.1 kardel 250 1.1 kardel struct parseunit; /* to keep inquiring minds happy */ 251 1.1 kardel 252 1.1 kardel typedef struct bind 253 1.1 kardel { 254 1.1 kardel const char *bd_description; /* name of type of binding */ 255 1.1 kardel int (*bd_init) (struct parseunit *); /* initialize */ 256 1.1 kardel void (*bd_end) (struct parseunit *); /* end */ 257 1.1 kardel int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */ 258 1.1 kardel int (*bd_disable) (struct parseunit *); /* disable */ 259 1.1 kardel int (*bd_enable) (struct parseunit *); /* enable */ 260 1.1 kardel int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */ 261 1.1 kardel int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */ 262 1.1 kardel int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */ 263 1.1 kardel void (*bd_receive) (struct recvbuf *); /* receive operation */ 264 1.1 kardel int (*bd_io_input) (struct recvbuf *); /* input operation */ 265 1.1 kardel } bind_t; 266 1.1 kardel 267 1.1 kardel #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) 268 1.1 kardel #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) 269 1.1 kardel #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) 270 1.1 kardel #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) 271 1.1 kardel #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) 272 1.1 kardel #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) 273 1.1 kardel #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) 274 1.1 kardel 275 1.1 kardel /* 276 1.5 kardel * special handling flags 277 1.1 kardel */ 278 1.5 kardel #define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */ 279 1.5 kardel #define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */ 280 1.5 kardel /* trusttime after SYNC was seen */ 281 1.1 kardel /**=========================================================================== 282 1.1 kardel ** error message regression handling 283 1.1 kardel ** 284 1.1 kardel ** there are quite a few errors that can occur in rapid succession such as 285 1.1 kardel ** noisy input data or no data at all. in order to reduce the amount of 286 1.1 kardel ** syslog messages in such case, we are using a backoff algorithm. We limit 287 1.1 kardel ** the number of error messages of a certain class to 1 per time unit. if a 288 1.1 kardel ** configurable number of messages is displayed that way, we move on to the 289 1.1 kardel ** next time unit / count for that class. a count of messages that have been 290 1.1 kardel ** suppressed is held and displayed whenever a corresponding message is 291 1.1 kardel ** displayed. the time units for a message class will also be displayed. 292 1.1 kardel ** whenever an error condition clears we reset the error message state, 293 1.1 kardel ** thus we would still generate much output on pathological conditions 294 1.1 kardel ** where the system oscillates between OK and NOT OK states. coping 295 1.1 kardel ** with that condition is currently considered too complicated. 296 1.1 kardel **/ 297 1.1 kardel 298 1.1 kardel #define ERR_ALL (unsigned)~0 /* "all" errors */ 299 1.1 kardel #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ 300 1.1 kardel #define ERR_NODATA (unsigned)1 /* no input data */ 301 1.1 kardel #define ERR_BADIO (unsigned)2 /* read/write/select errors */ 302 1.1 kardel #define ERR_BADSTATUS (unsigned)3 /* unsync states */ 303 1.1 kardel #define ERR_BADEVENT (unsigned)4 /* non nominal events */ 304 1.1 kardel #define ERR_INTERNAL (unsigned)5 /* internal error */ 305 1.1 kardel #define ERR_CNT (unsigned)(ERR_INTERNAL+1) 306 1.1 kardel 307 1.1 kardel #define ERR(_X_) if (list_err(parse, (_X_))) 308 1.1 kardel 309 1.1 kardel struct errorregression 310 1.1 kardel { 311 1.1 kardel u_long err_count; /* number of repititions per class */ 312 1.1 kardel u_long err_delay; /* minimum delay between messages */ 313 1.1 kardel }; 314 1.1 kardel 315 1.1 kardel static struct errorregression 316 1.1 kardel err_baddata[] = /* error messages for bad input data */ 317 1.1 kardel { 318 1.1 kardel { 1, 0 }, /* output first message immediately */ 319 1.1 kardel { 5, 60 }, /* output next five messages in 60 second intervals */ 320 1.1 kardel { 3, 3600 }, /* output next 3 messages in hour intervals */ 321 1.1 kardel { 0, 12*3600 } /* repeat messages only every 12 hours */ 322 1.1 kardel }; 323 1.1 kardel 324 1.1 kardel static struct errorregression 325 1.1 kardel err_nodata[] = /* error messages for missing input data */ 326 1.1 kardel { 327 1.1 kardel { 1, 0 }, /* output first message immediately */ 328 1.1 kardel { 5, 60 }, /* output next five messages in 60 second intervals */ 329 1.1 kardel { 3, 3600 }, /* output next 3 messages in hour intervals */ 330 1.1 kardel { 0, 12*3600 } /* repeat messages only every 12 hours */ 331 1.1 kardel }; 332 1.1 kardel 333 1.1 kardel static struct errorregression 334 1.1 kardel err_badstatus[] = /* unsynchronized state messages */ 335 1.1 kardel { 336 1.1 kardel { 1, 0 }, /* output first message immediately */ 337 1.1 kardel { 5, 60 }, /* output next five messages in 60 second intervals */ 338 1.1 kardel { 3, 3600 }, /* output next 3 messages in hour intervals */ 339 1.1 kardel { 0, 12*3600 } /* repeat messages only every 12 hours */ 340 1.1 kardel }; 341 1.1 kardel 342 1.1 kardel static struct errorregression 343 1.1 kardel err_badio[] = /* io failures (bad reads, selects, ...) */ 344 1.1 kardel { 345 1.1 kardel { 1, 0 }, /* output first message immediately */ 346 1.1 kardel { 5, 60 }, /* output next five messages in 60 second intervals */ 347 1.1 kardel { 5, 3600 }, /* output next 3 messages in hour intervals */ 348 1.1 kardel { 0, 12*3600 } /* repeat messages only every 12 hours */ 349 1.1 kardel }; 350 1.1 kardel 351 1.1 kardel static struct errorregression 352 1.1 kardel err_badevent[] = /* non nominal events */ 353 1.1 kardel { 354 1.1 kardel { 20, 0 }, /* output first message immediately */ 355 1.1 kardel { 6, 60 }, /* output next five messages in 60 second intervals */ 356 1.1 kardel { 5, 3600 }, /* output next 3 messages in hour intervals */ 357 1.1 kardel { 0, 12*3600 } /* repeat messages only every 12 hours */ 358 1.1 kardel }; 359 1.1 kardel 360 1.1 kardel static struct errorregression 361 1.1 kardel err_internal[] = /* really bad things - basically coding/OS errors */ 362 1.1 kardel { 363 1.1 kardel { 0, 0 }, /* output all messages immediately */ 364 1.1 kardel }; 365 1.1 kardel 366 1.1 kardel static struct errorregression * 367 1.1 kardel err_tbl[] = 368 1.1 kardel { 369 1.1 kardel err_baddata, 370 1.1 kardel err_nodata, 371 1.1 kardel err_badio, 372 1.1 kardel err_badstatus, 373 1.1 kardel err_badevent, 374 1.1 kardel err_internal 375 1.1 kardel }; 376 1.1 kardel 377 1.1 kardel struct errorinfo 378 1.1 kardel { 379 1.1 kardel u_long err_started; /* begin time (ntp) of error condition */ 380 1.1 kardel u_long err_last; /* last time (ntp) error occurred */ 381 1.1 kardel u_long err_cnt; /* number of error repititions */ 382 1.1 kardel u_long err_suppressed; /* number of suppressed messages */ 383 1.1 kardel struct errorregression *err_stage; /* current error stage */ 384 1.1 kardel }; 385 1.1 kardel 386 1.1 kardel /**=========================================================================== 387 1.1 kardel ** refclock instance data 388 1.1 kardel **/ 389 1.1 kardel 390 1.1 kardel struct parseunit 391 1.1 kardel { 392 1.1 kardel /* 393 1.1 kardel * NTP management 394 1.1 kardel */ 395 1.1 kardel struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 396 1.1 kardel struct refclockproc *generic; /* backlink to refclockproc structure */ 397 1.1 kardel 398 1.1 kardel /* 399 1.1 kardel * PARSE io 400 1.1 kardel */ 401 1.1 kardel bind_t *binding; /* io handling binding */ 402 1.15 christos 403 1.1 kardel /* 404 1.1 kardel * parse state 405 1.1 kardel */ 406 1.1 kardel parse_t parseio; /* io handling structure (user level parsing) */ 407 1.1 kardel 408 1.1 kardel /* 409 1.1 kardel * type specific parameters 410 1.1 kardel */ 411 1.1 kardel struct parse_clockinfo *parse_type; /* link to clock description */ 412 1.1 kardel 413 1.1 kardel /* 414 1.1 kardel * clock state handling/reporting 415 1.1 kardel */ 416 1.1 kardel u_char flags; /* flags (leap_control) */ 417 1.1 kardel u_long lastchange; /* time (ntp) when last state change accured */ 418 1.1 kardel u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ 419 1.1 kardel u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ 420 1.1 kardel u_short lastformat; /* last format used */ 421 1.1 kardel u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ 422 1.1 kardel u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */ 423 1.1 kardel double ppsphaseadjust; /* phase adjustment of PPS time stamp */ 424 1.1 kardel u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ 425 1.1 kardel u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ 426 1.1 kardel int ppsfd; /* fd to ise for PPS io */ 427 1.1 kardel #ifdef HAVE_PPSAPI 428 1.1 kardel int hardppsstate; /* current hard pps state */ 429 1.1 kardel struct refclock_atom atom; /* PPSAPI structure */ 430 1.1 kardel #endif 431 1.1 kardel parsetime_t timedata; /* last (parse module) data */ 432 1.1 kardel void *localdata; /* optional local, receiver-specific data */ 433 1.1 kardel unsigned long localstate; /* private local state */ 434 1.1 kardel struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ 435 1.1 kardel struct ctl_var *kv; /* additional pseudo variables */ 436 1.1 kardel u_long laststatistic; /* time when staticstics where output */ 437 1.1 kardel }; 438 1.1 kardel 439 1.1 kardel 440 1.1 kardel /**=========================================================================== 441 1.1 kardel ** Clockinfo section all parameter for specific clock types 442 1.1 kardel ** includes NTP parameters, TTY parameters and IO handling parameters 443 1.1 kardel **/ 444 1.1 kardel 445 1.1 kardel static void poll_dpoll (struct parseunit *); 446 1.1 kardel static void poll_poll (struct peer *); 447 1.1 kardel static int poll_init (struct parseunit *); 448 1.1 kardel 449 1.1 kardel typedef struct poll_info 450 1.1 kardel { 451 1.1 kardel u_long rate; /* poll rate - once every "rate" seconds - 0 off */ 452 1.1 kardel const char *string; /* string to send for polling */ 453 1.1 kardel u_long count; /* number of characters in string */ 454 1.1 kardel } poll_info_t; 455 1.1 kardel 456 1.1 kardel #define NO_CL_FLAGS 0 457 1.1 kardel #define NO_POLL 0 458 1.1 kardel #define NO_INIT 0 459 1.1 kardel #define NO_END 0 460 1.1 kardel #define NO_EVENT 0 461 1.1 kardel #define NO_LCLDATA 0 462 1.1 kardel #define NO_MESSAGE 0 463 1.1 kardel #define NO_PPSDELAY 0 464 1.1 kardel 465 1.1 kardel #define DCF_ID "DCF" /* generic DCF */ 466 1.1 kardel #define DCF_A_ID "DCFa" /* AM demodulation */ 467 1.1 kardel #define DCF_P_ID "DCFp" /* psuedo random phase shift */ 468 1.1 kardel #define GPS_ID "GPS" /* GPS receiver */ 469 1.1 kardel 470 1.15 christos #define NOCLOCK_ROOTDELAY 0.0 471 1.15 christos #define NOCLOCK_BASEDELAY 0.0 472 1.15 christos #define NOCLOCK_DESCRIPTION 0 473 1.1 kardel #define NOCLOCK_MAXUNSYNC 0 474 1.1 kardel #define NOCLOCK_CFLAG 0 475 1.1 kardel #define NOCLOCK_IFLAG 0 476 1.1 kardel #define NOCLOCK_OFLAG 0 477 1.1 kardel #define NOCLOCK_LFLAG 0 478 1.15 christos #define NOCLOCK_ID "TILT" 479 1.15 christos #define NOCLOCK_POLL NO_POLL 480 1.15 christos #define NOCLOCK_INIT NO_INIT 481 1.15 christos #define NOCLOCK_END NO_END 482 1.15 christos #define NOCLOCK_DATA NO_LCLDATA 483 1.15 christos #define NOCLOCK_FORMAT "" 484 1.15 christos #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 485 1.15 christos #define NOCLOCK_SAMPLES 0 486 1.15 christos #define NOCLOCK_KEEP 0 487 1.1 kardel 488 1.1 kardel #define DCF_TYPE CTL_SST_TS_LF 489 1.1 kardel #define GPS_TYPE CTL_SST_TS_UHF 490 1.1 kardel 491 1.1 kardel /* 492 1.1 kardel * receiver specific constants 493 1.1 kardel */ 494 1.1 kardel #define MBG_SPEED (B9600) 495 1.1 kardel #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB) 496 1.1 kardel #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 497 1.1 kardel #define MBG_OFLAG 0 498 1.1 kardel #define MBG_LFLAG 0 499 1.1 kardel #define MBG_FLAGS PARSE_F_PPSONSECOND 500 1.1 kardel 501 1.1 kardel /* 502 1.1 kardel * Meinberg DCF77 receivers 503 1.1 kardel */ 504 1.1 kardel #define DCFUA31_ROOTDELAY 0.0 /* 0 */ 505 1.1 kardel #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ 506 1.1 kardel #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" 507 1.1 kardel #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ 508 1.1 kardel #define DCFUA31_SPEED MBG_SPEED 509 1.1 kardel #define DCFUA31_CFLAG MBG_CFLAG 510 1.1 kardel #define DCFUA31_IFLAG MBG_IFLAG 511 1.1 kardel #define DCFUA31_OFLAG MBG_OFLAG 512 1.1 kardel #define DCFUA31_LFLAG MBG_LFLAG 513 1.1 kardel #define DCFUA31_SAMPLES 5 514 1.1 kardel #define DCFUA31_KEEP 3 515 1.1 kardel #define DCFUA31_FORMAT "Meinberg Standard" 516 1.1 kardel 517 1.1 kardel /* 518 1.1 kardel * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 519 1.1 kardel */ 520 1.1 kardel #define DCFPZF535_ROOTDELAY 0.0 521 1.1 kardel #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 522 1.1 kardel #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" 523 1.1 kardel #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours 524 1.1 kardel * @ 5e-8df/f we have accumulated 525 1.1 kardel * at most 2.16 ms (thus we move to 526 1.1 kardel * NTP synchronisation */ 527 1.1 kardel #define DCFPZF535_SPEED MBG_SPEED 528 1.1 kardel #define DCFPZF535_CFLAG MBG_CFLAG 529 1.1 kardel #define DCFPZF535_IFLAG MBG_IFLAG 530 1.1 kardel #define DCFPZF535_OFLAG MBG_OFLAG 531 1.1 kardel #define DCFPZF535_LFLAG MBG_LFLAG 532 1.1 kardel #define DCFPZF535_SAMPLES 5 533 1.1 kardel #define DCFPZF535_KEEP 3 534 1.1 kardel #define DCFPZF535_FORMAT "Meinberg Standard" 535 1.1 kardel 536 1.1 kardel /* 537 1.1 kardel * Meinberg DCF PZF535/OCXO receiver 538 1.1 kardel */ 539 1.1 kardel #define DCFPZF535OCXO_ROOTDELAY 0.0 540 1.1 kardel #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 541 1.1 kardel #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" 542 1.1 kardel #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 543 1.1 kardel * @ 5e-9df/f we have accumulated 544 1.1 kardel * at most an error of 1.73 ms 545 1.1 kardel * (thus we move to NTP synchronisation) */ 546 1.1 kardel #define DCFPZF535OCXO_SPEED MBG_SPEED 547 1.1 kardel #define DCFPZF535OCXO_CFLAG MBG_CFLAG 548 1.1 kardel #define DCFPZF535OCXO_IFLAG MBG_IFLAG 549 1.1 kardel #define DCFPZF535OCXO_OFLAG MBG_OFLAG 550 1.1 kardel #define DCFPZF535OCXO_LFLAG MBG_LFLAG 551 1.1 kardel #define DCFPZF535OCXO_SAMPLES 5 552 1.1 kardel #define DCFPZF535OCXO_KEEP 3 553 1.1 kardel #define DCFPZF535OCXO_FORMAT "Meinberg Standard" 554 1.1 kardel 555 1.1 kardel /* 556 1.15 christos * Meinberg GPS receivers 557 1.1 kardel */ 558 1.1 kardel static void gps16x_message (struct parseunit *, parsetime_t *); 559 1.1 kardel static int gps16x_poll_init (struct parseunit *); 560 1.1 kardel 561 1.1 kardel #define GPS16X_ROOTDELAY 0.0 /* nothing here */ 562 1.1 kardel #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 563 1.15 christos #define GPS16X_DESCRIPTION "Meinberg GPS receiver" 564 1.1 kardel #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 565 1.1 kardel * @ 5e-9df/f we have accumulated 566 1.1 kardel * at most an error of 1.73 ms 567 1.1 kardel * (thus we move to NTP synchronisation) */ 568 1.1 kardel #define GPS16X_SPEED B19200 569 1.1 kardel #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) 570 1.1 kardel #define GPS16X_IFLAG (IGNBRK|IGNPAR) 571 1.1 kardel #define GPS16X_OFLAG MBG_OFLAG 572 1.1 kardel #define GPS16X_LFLAG MBG_LFLAG 573 1.1 kardel #define GPS16X_POLLRATE 6 574 1.1 kardel #define GPS16X_POLLCMD "" 575 1.1 kardel #define GPS16X_CMDSIZE 0 576 1.1 kardel 577 1.1 kardel static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 578 1.1 kardel 579 1.1 kardel #define GPS16X_INIT gps16x_poll_init 580 1.1 kardel #define GPS16X_POLL 0 581 1.1 kardel #define GPS16X_END 0 582 1.1 kardel #define GPS16X_DATA ((void *)(&gps16x_pollinfo)) 583 1.1 kardel #define GPS16X_MESSAGE gps16x_message 584 1.1 kardel #define GPS16X_ID GPS_ID 585 1.1 kardel #define GPS16X_FORMAT "Meinberg GPS Extended" 586 1.1 kardel #define GPS16X_SAMPLES 5 587 1.1 kardel #define GPS16X_KEEP 3 588 1.1 kardel 589 1.1 kardel /* 590 1.1 kardel * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 591 1.1 kardel * 592 1.1 kardel * This is really not the hottest clock - but before you have nothing ... 593 1.1 kardel */ 594 1.1 kardel #define DCF7000_ROOTDELAY 0.0 /* 0 */ 595 1.1 kardel #define DCF7000_BASEDELAY 0.405 /* slow blow */ 596 1.1 kardel #define DCF7000_DESCRIPTION "ELV DCF7000" 597 1.1 kardel #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ 598 1.1 kardel #define DCF7000_SPEED (B9600) 599 1.1 kardel #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) 600 1.1 kardel #define DCF7000_IFLAG (IGNBRK) 601 1.1 kardel #define DCF7000_OFLAG 0 602 1.1 kardel #define DCF7000_LFLAG 0 603 1.1 kardel #define DCF7000_SAMPLES 5 604 1.1 kardel #define DCF7000_KEEP 3 605 1.1 kardel #define DCF7000_FORMAT "ELV DCF7000" 606 1.1 kardel 607 1.1 kardel /* 608 1.1 kardel * Schmid DCF Receiver Kit 609 1.1 kardel * 610 1.1 kardel * When the WSDCF clock is operating optimally we want the primary clock 611 1.1 kardel * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer 612 1.1 kardel * structure is set to 290 ms and we compute delays which are at least 613 1.1 kardel * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format 614 1.1 kardel */ 615 1.1 kardel #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 616 1.1 kardel #define WS_POLLCMD "\163" 617 1.1 kardel #define WS_CMDSIZE 1 618 1.1 kardel 619 1.1 kardel static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 620 1.1 kardel 621 1.1 kardel #define WSDCF_INIT poll_init 622 1.1 kardel #define WSDCF_POLL poll_dpoll 623 1.1 kardel #define WSDCF_END 0 624 1.1 kardel #define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) 625 1.1 kardel #define WSDCF_ROOTDELAY 0.0 /* 0 */ 626 1.1 kardel #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ 627 1.1 kardel #define WSDCF_DESCRIPTION "WS/DCF Receiver" 628 1.1 kardel #define WSDCF_FORMAT "Schmid" 629 1.1 kardel #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ 630 1.1 kardel #define WSDCF_SPEED (B1200) 631 1.1 kardel #define WSDCF_CFLAG (CS8|CREAD|CLOCAL) 632 1.1 kardel #define WSDCF_IFLAG 0 633 1.1 kardel #define WSDCF_OFLAG 0 634 1.1 kardel #define WSDCF_LFLAG 0 635 1.1 kardel #define WSDCF_SAMPLES 5 636 1.1 kardel #define WSDCF_KEEP 3 637 1.1 kardel 638 1.1 kardel /* 639 1.1 kardel * RAW DCF77 - input of DCF marks via RS232 - many variants 640 1.1 kardel */ 641 1.1 kardel #define RAWDCF_FLAGS 0 642 1.1 kardel #define RAWDCF_ROOTDELAY 0.0 /* 0 */ 643 1.1 kardel #define RAWDCF_BASEDELAY 0.258 644 1.1 kardel #define RAWDCF_FORMAT "RAW DCF77 Timecode" 645 1.1 kardel #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ 646 1.1 kardel #define RAWDCF_SPEED (B50) 647 1.1 kardel #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ 648 1.1 kardel /* somehow doesn't grok PARENB & IGNPAR (mj) */ 649 1.1 kardel # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) 650 1.1 kardel #else 651 1.1 kardel # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 652 1.1 kardel #endif 653 1.1 kardel #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 654 1.1 kardel # define RAWDCF_IFLAG 0 655 1.1 kardel #else 656 1.1 kardel # define RAWDCF_IFLAG (IGNPAR) 657 1.1 kardel #endif 658 1.1 kardel #define RAWDCF_OFLAG 0 659 1.1 kardel #define RAWDCF_LFLAG 0 660 1.1 kardel #define RAWDCF_SAMPLES 20 661 1.1 kardel #define RAWDCF_KEEP 12 662 1.1 kardel #define RAWDCF_INIT 0 663 1.1 kardel 664 1.1 kardel /* 665 1.1 kardel * RAW DCF variants 666 1.1 kardel */ 667 1.1 kardel /* 668 1.1 kardel * Conrad receiver 669 1.1 kardel * 670 1.1 kardel * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 671 1.1 kardel * (~40DM - roughly $30 ) followed by a level converter for RS232 672 1.1 kardel */ 673 1.1 kardel #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 674 1.1 kardel #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 675 1.1 kardel 676 1.1 kardel /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */ 677 1.1 kardel #define GUDE_EMC_USB_V20_SPEED (B4800) 678 1.1 kardel #define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */ 679 1.1 kardel #define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)" 680 1.1 kardel 681 1.1 kardel /* 682 1.1 kardel * TimeBrick receiver 683 1.1 kardel */ 684 1.1 kardel #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 685 1.1 kardel #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 686 1.1 kardel 687 1.1 kardel /* 688 1.1 kardel * IGEL:clock receiver 689 1.1 kardel */ 690 1.1 kardel #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ 691 1.1 kardel #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" 692 1.1 kardel #define IGELCLOCK_SPEED (B1200) 693 1.1 kardel #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) 694 1.1 kardel 695 1.1 kardel /* 696 1.1 kardel * RAWDCF receivers that need to be powered from DTR 697 1.1 kardel * (like Expert mouse clock) 698 1.1 kardel */ 699 1.1 kardel static int rawdcf_init_1 (struct parseunit *); 700 1.1 kardel #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 701 1.5 kardel #define RAWDCFDTRSET75_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)" 702 1.1 kardel #define RAWDCFDTRSET_INIT rawdcf_init_1 703 1.1 kardel 704 1.1 kardel /* 705 1.1 kardel * RAWDCF receivers that need to be powered from 706 1.1 kardel * DTR CLR and RTS SET 707 1.1 kardel */ 708 1.1 kardel static int rawdcf_init_2 (struct parseunit *); 709 1.1 kardel #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 710 1.5 kardel #define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)" 711 1.1 kardel #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 712 1.1 kardel 713 1.1 kardel /* 714 1.1 kardel * Trimble GPS receivers (TAIP and TSIP protocols) 715 1.1 kardel */ 716 1.1 kardel #ifndef TRIM_POLLRATE 717 1.1 kardel #define TRIM_POLLRATE 0 /* only true direct polling */ 718 1.1 kardel #endif 719 1.1 kardel 720 1.1 kardel #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 721 1.1 kardel #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 722 1.1 kardel 723 1.1 kardel static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 724 1.1 kardel static int trimbletaip_init (struct parseunit *); 725 1.1 kardel static void trimbletaip_event (struct parseunit *, int); 726 1.1 kardel 727 1.1 kardel /* query time & UTC correction data */ 728 1.1 kardel static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 729 1.1 kardel 730 1.1 kardel static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 731 1.1 kardel static int trimbletsip_init (struct parseunit *); 732 1.1 kardel static void trimbletsip_end (struct parseunit *); 733 1.1 kardel static void trimbletsip_message (struct parseunit *, parsetime_t *); 734 1.1 kardel static void trimbletsip_event (struct parseunit *, int); 735 1.1 kardel 736 1.1 kardel #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 737 1.1 kardel #define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME 738 1.1 kardel 739 1.1 kardel #define TRIMBLETAIP_SPEED (B4800) 740 1.1 kardel #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 741 1.1 kardel #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 742 1.1 kardel #define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 743 1.1 kardel #define TRIMBLETAIP_LFLAG (0) 744 1.1 kardel 745 1.1 kardel #define TRIMBLETSIP_SPEED (B9600) 746 1.1 kardel #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 747 1.1 kardel #define TRIMBLETSIP_IFLAG (IGNBRK) 748 1.1 kardel #define TRIMBLETSIP_OFLAG (0) 749 1.1 kardel #define TRIMBLETSIP_LFLAG (ICANON) 750 1.1 kardel 751 1.1 kardel #define TRIMBLETSIP_SAMPLES 5 752 1.1 kardel #define TRIMBLETSIP_KEEP 3 753 1.1 kardel #define TRIMBLETAIP_SAMPLES 5 754 1.1 kardel #define TRIMBLETAIP_KEEP 3 755 1.1 kardel 756 1.1 kardel #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 757 1.1 kardel #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 758 1.1 kardel 759 1.1 kardel #define TRIMBLETAIP_POLL poll_dpoll 760 1.1 kardel #define TRIMBLETSIP_POLL poll_dpoll 761 1.1 kardel 762 1.1 kardel #define TRIMBLETAIP_INIT trimbletaip_init 763 1.1 kardel #define TRIMBLETSIP_INIT trimbletsip_init 764 1.1 kardel 765 1.15 christos #define TRIMBLETAIP_EVENT trimbletaip_event 766 1.1 kardel 767 1.15 christos #define TRIMBLETSIP_EVENT trimbletsip_event 768 1.1 kardel #define TRIMBLETSIP_MESSAGE trimbletsip_message 769 1.1 kardel 770 1.1 kardel #define TRIMBLETAIP_END 0 771 1.1 kardel #define TRIMBLETSIP_END trimbletsip_end 772 1.1 kardel 773 1.1 kardel #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 774 1.1 kardel #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 775 1.1 kardel 776 1.1 kardel #define TRIMBLETAIP_ID GPS_ID 777 1.1 kardel #define TRIMBLETSIP_ID GPS_ID 778 1.1 kardel 779 1.1 kardel #define TRIMBLETAIP_FORMAT "Trimble TAIP" 780 1.1 kardel #define TRIMBLETSIP_FORMAT "Trimble TSIP" 781 1.1 kardel 782 1.1 kardel #define TRIMBLETAIP_ROOTDELAY 0x0 783 1.1 kardel #define TRIMBLETSIP_ROOTDELAY 0x0 784 1.1 kardel 785 1.1 kardel #define TRIMBLETAIP_BASEDELAY 0.0 786 1.1 kardel #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 787 1.1 kardel 788 1.1 kardel #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 789 1.1 kardel #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 790 1.1 kardel 791 1.1 kardel #define TRIMBLETAIP_MAXUNSYNC 0 792 1.1 kardel #define TRIMBLETSIP_MAXUNSYNC 0 793 1.1 kardel 794 1.1 kardel #define TRIMBLETAIP_EOL '<' 795 1.1 kardel 796 1.1 kardel /* 797 1.1 kardel * RadioCode Clocks RCC 800 receiver 798 1.1 kardel */ 799 1.1 kardel #define RCC_POLLRATE 0 /* only true direct polling */ 800 1.1 kardel #define RCC_POLLCMD "\r" 801 1.1 kardel #define RCC_CMDSIZE 1 802 1.1 kardel 803 1.1 kardel static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 804 1.1 kardel #define RCC8000_FLAGS 0 805 1.1 kardel #define RCC8000_POLL poll_dpoll 806 1.1 kardel #define RCC8000_INIT poll_init 807 1.1 kardel #define RCC8000_END 0 808 1.1 kardel #define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 809 1.1 kardel #define RCC8000_ROOTDELAY 0.0 810 1.1 kardel #define RCC8000_BASEDELAY 0.0 811 1.1 kardel #define RCC8000_ID "MSF" 812 1.1 kardel #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 813 1.1 kardel #define RCC8000_FORMAT "Radiocode RCC8000" 814 1.1 kardel #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 815 1.1 kardel #define RCC8000_SPEED (B2400) 816 1.1 kardel #define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 817 1.1 kardel #define RCC8000_IFLAG (IGNBRK|IGNPAR) 818 1.1 kardel #define RCC8000_OFLAG 0 819 1.1 kardel #define RCC8000_LFLAG 0 820 1.1 kardel #define RCC8000_SAMPLES 5 821 1.1 kardel #define RCC8000_KEEP 3 822 1.1 kardel 823 1.1 kardel /* 824 1.15 christos * Hopf Radio clock 6021 Format 825 1.1 kardel * 826 1.1 kardel */ 827 1.1 kardel #define HOPF6021_ROOTDELAY 0.0 828 1.1 kardel #define HOPF6021_BASEDELAY 0.0 829 1.1 kardel #define HOPF6021_DESCRIPTION "HOPF 6021" 830 1.1 kardel #define HOPF6021_FORMAT "hopf Funkuhr 6021" 831 1.1 kardel #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 832 1.1 kardel #define HOPF6021_SPEED (B9600) 833 1.1 kardel #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 834 1.1 kardel #define HOPF6021_IFLAG (IGNBRK|ISTRIP) 835 1.1 kardel #define HOPF6021_OFLAG 0 836 1.1 kardel #define HOPF6021_LFLAG 0 837 1.1 kardel #define HOPF6021_FLAGS 0 838 1.1 kardel #define HOPF6021_SAMPLES 5 839 1.1 kardel #define HOPF6021_KEEP 3 840 1.1 kardel 841 1.1 kardel /* 842 1.1 kardel * Diem's Computime Radio Clock Receiver 843 1.1 kardel */ 844 1.1 kardel #define COMPUTIME_FLAGS 0 845 1.1 kardel #define COMPUTIME_ROOTDELAY 0.0 846 1.1 kardel #define COMPUTIME_BASEDELAY 0.0 847 1.1 kardel #define COMPUTIME_ID DCF_ID 848 1.1 kardel #define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 849 1.1 kardel #define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 850 1.1 kardel #define COMPUTIME_TYPE DCF_TYPE 851 1.1 kardel #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 852 1.1 kardel #define COMPUTIME_SPEED (B9600) 853 1.1 kardel #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 854 1.1 kardel #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 855 1.1 kardel #define COMPUTIME_OFLAG 0 856 1.1 kardel #define COMPUTIME_LFLAG 0 857 1.1 kardel #define COMPUTIME_SAMPLES 5 858 1.1 kardel #define COMPUTIME_KEEP 3 859 1.1 kardel 860 1.1 kardel /* 861 1.1 kardel * Varitext Radio Clock Receiver 862 1.1 kardel */ 863 1.1 kardel #define VARITEXT_FLAGS 0 864 1.1 kardel #define VARITEXT_ROOTDELAY 0.0 865 1.1 kardel #define VARITEXT_BASEDELAY 0.0 866 1.1 kardel #define VARITEXT_ID "MSF" 867 1.1 kardel #define VARITEXT_DESCRIPTION "Varitext receiver" 868 1.1 kardel #define VARITEXT_FORMAT "Varitext Radio Clock" 869 1.1 kardel #define VARITEXT_TYPE DCF_TYPE 870 1.1 kardel #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 871 1.1 kardel #define VARITEXT_SPEED (B9600) 872 1.1 kardel #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 873 1.1 kardel #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 874 1.1 kardel #define VARITEXT_OFLAG 0 875 1.1 kardel #define VARITEXT_LFLAG 0 876 1.1 kardel #define VARITEXT_SAMPLES 32 877 1.1 kardel #define VARITEXT_KEEP 20 878 1.1 kardel 879 1.10 christos /* 880 1.10 christos * SEL240x Satellite Sychronized Clock 881 1.10 christos */ 882 1.10 christos #define SEL240X_POLLRATE 0 /* only true direct polling */ 883 1.10 christos #define SEL240X_POLLCMD "BUB8" 884 1.10 christos #define SEL240X_CMDSIZE 4 885 1.10 christos 886 1.10 christos static poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE, 887 1.10 christos SEL240X_POLLCMD, 888 1.10 christos SEL240X_CMDSIZE }; 889 1.10 christos #define SEL240X_FLAGS (PARSE_F_PPSONSECOND) 890 1.10 christos #define SEL240X_POLL poll_dpoll 891 1.10 christos #define SEL240X_INIT poll_init 892 1.10 christos #define SEL240X_END 0 893 1.10 christos #define SEL240X_DATA ((void *)(&sel240x_pollinfo)) 894 1.10 christos #define SEL240X_ROOTDELAY 0.0 895 1.10 christos #define SEL240X_BASEDELAY 0.0 896 1.10 christos #define SEL240X_ID GPS_ID 897 1.10 christos #define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock" 898 1.10 christos #define SEL240X_FORMAT "SEL B8" 899 1.10 christos #define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */ 900 1.10 christos #define SEL240X_SPEED (B9600) 901 1.10 christos #define SEL240X_CFLAG (CS8|CREAD|CLOCAL) 902 1.10 christos #define SEL240X_IFLAG (IGNBRK|IGNPAR) 903 1.10 christos #define SEL240X_OFLAG (0) 904 1.10 christos #define SEL240X_LFLAG (0) 905 1.10 christos #define SEL240X_SAMPLES 5 906 1.10 christos #define SEL240X_KEEP 3 907 1.10 christos 908 1.1 kardel static struct parse_clockinfo 909 1.1 kardel { 910 1.5 kardel u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */ 911 1.1 kardel void (*cl_poll) (struct parseunit *); /* active poll routine */ 912 1.1 kardel int (*cl_init) (struct parseunit *); /* active poll init routine */ 913 1.1 kardel void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */ 914 1.1 kardel void (*cl_end) (struct parseunit *); /* active poll end routine */ 915 1.1 kardel void (*cl_message) (struct parseunit *, parsetime_t *); /* process a lower layer message */ 916 1.1 kardel void *cl_data; /* local data area for "poll" mechanism */ 917 1.1 kardel double cl_rootdelay; /* rootdelay */ 918 1.1 kardel double cl_basedelay; /* current offset by which the RS232 919 1.1 kardel time code is delayed from the actual time */ 920 1.1 kardel const char *cl_id; /* ID code */ 921 1.1 kardel const char *cl_description; /* device name */ 922 1.1 kardel const char *cl_format; /* fixed format */ 923 1.1 kardel u_char cl_type; /* clock type (ntp control) */ 924 1.1 kardel u_long cl_maxunsync; /* time to trust oscillator after losing synch */ 925 1.1 kardel u_long cl_speed; /* terminal input & output baudrate */ 926 1.1 kardel u_long cl_cflag; /* terminal control flags */ 927 1.1 kardel u_long cl_iflag; /* terminal input flags */ 928 1.1 kardel u_long cl_oflag; /* terminal output flags */ 929 1.1 kardel u_long cl_lflag; /* terminal local flags */ 930 1.1 kardel u_long cl_samples; /* samples for median filter */ 931 1.1 kardel u_long cl_keep; /* samples for median filter to keep */ 932 1.1 kardel } parse_clockinfo[] = 933 1.1 kardel { 934 1.1 kardel { /* mode 0 */ 935 1.1 kardel MBG_FLAGS, 936 1.1 kardel NO_POLL, 937 1.1 kardel NO_INIT, 938 1.1 kardel NO_EVENT, 939 1.1 kardel NO_END, 940 1.1 kardel NO_MESSAGE, 941 1.1 kardel NO_LCLDATA, 942 1.1 kardel DCFPZF535_ROOTDELAY, 943 1.1 kardel DCFPZF535_BASEDELAY, 944 1.1 kardel DCF_P_ID, 945 1.1 kardel DCFPZF535_DESCRIPTION, 946 1.1 kardel DCFPZF535_FORMAT, 947 1.1 kardel DCF_TYPE, 948 1.1 kardel DCFPZF535_MAXUNSYNC, 949 1.1 kardel DCFPZF535_SPEED, 950 1.1 kardel DCFPZF535_CFLAG, 951 1.1 kardel DCFPZF535_IFLAG, 952 1.1 kardel DCFPZF535_OFLAG, 953 1.1 kardel DCFPZF535_LFLAG, 954 1.1 kardel DCFPZF535_SAMPLES, 955 1.1 kardel DCFPZF535_KEEP 956 1.1 kardel }, 957 1.1 kardel { /* mode 1 */ 958 1.1 kardel MBG_FLAGS, 959 1.1 kardel NO_POLL, 960 1.1 kardel NO_INIT, 961 1.1 kardel NO_EVENT, 962 1.1 kardel NO_END, 963 1.1 kardel NO_MESSAGE, 964 1.1 kardel NO_LCLDATA, 965 1.1 kardel DCFPZF535OCXO_ROOTDELAY, 966 1.1 kardel DCFPZF535OCXO_BASEDELAY, 967 1.1 kardel DCF_P_ID, 968 1.1 kardel DCFPZF535OCXO_DESCRIPTION, 969 1.1 kardel DCFPZF535OCXO_FORMAT, 970 1.1 kardel DCF_TYPE, 971 1.1 kardel DCFPZF535OCXO_MAXUNSYNC, 972 1.1 kardel DCFPZF535OCXO_SPEED, 973 1.1 kardel DCFPZF535OCXO_CFLAG, 974 1.1 kardel DCFPZF535OCXO_IFLAG, 975 1.1 kardel DCFPZF535OCXO_OFLAG, 976 1.1 kardel DCFPZF535OCXO_LFLAG, 977 1.1 kardel DCFPZF535OCXO_SAMPLES, 978 1.1 kardel DCFPZF535OCXO_KEEP 979 1.1 kardel }, 980 1.1 kardel { /* mode 2 */ 981 1.1 kardel MBG_FLAGS, 982 1.1 kardel NO_POLL, 983 1.1 kardel NO_INIT, 984 1.1 kardel NO_EVENT, 985 1.1 kardel NO_END, 986 1.1 kardel NO_MESSAGE, 987 1.1 kardel NO_LCLDATA, 988 1.1 kardel DCFUA31_ROOTDELAY, 989 1.1 kardel DCFUA31_BASEDELAY, 990 1.1 kardel DCF_A_ID, 991 1.1 kardel DCFUA31_DESCRIPTION, 992 1.1 kardel DCFUA31_FORMAT, 993 1.1 kardel DCF_TYPE, 994 1.1 kardel DCFUA31_MAXUNSYNC, 995 1.1 kardel DCFUA31_SPEED, 996 1.1 kardel DCFUA31_CFLAG, 997 1.1 kardel DCFUA31_IFLAG, 998 1.1 kardel DCFUA31_OFLAG, 999 1.1 kardel DCFUA31_LFLAG, 1000 1.1 kardel DCFUA31_SAMPLES, 1001 1.1 kardel DCFUA31_KEEP 1002 1.1 kardel }, 1003 1.1 kardel { /* mode 3 */ 1004 1.1 kardel MBG_FLAGS, 1005 1.1 kardel NO_POLL, 1006 1.1 kardel NO_INIT, 1007 1.1 kardel NO_EVENT, 1008 1.1 kardel NO_END, 1009 1.1 kardel NO_MESSAGE, 1010 1.1 kardel NO_LCLDATA, 1011 1.1 kardel DCF7000_ROOTDELAY, 1012 1.1 kardel DCF7000_BASEDELAY, 1013 1.1 kardel DCF_A_ID, 1014 1.1 kardel DCF7000_DESCRIPTION, 1015 1.1 kardel DCF7000_FORMAT, 1016 1.1 kardel DCF_TYPE, 1017 1.1 kardel DCF7000_MAXUNSYNC, 1018 1.1 kardel DCF7000_SPEED, 1019 1.1 kardel DCF7000_CFLAG, 1020 1.1 kardel DCF7000_IFLAG, 1021 1.1 kardel DCF7000_OFLAG, 1022 1.1 kardel DCF7000_LFLAG, 1023 1.1 kardel DCF7000_SAMPLES, 1024 1.1 kardel DCF7000_KEEP 1025 1.1 kardel }, 1026 1.1 kardel { /* mode 4 */ 1027 1.1 kardel NO_CL_FLAGS, 1028 1.1 kardel WSDCF_POLL, 1029 1.1 kardel WSDCF_INIT, 1030 1.1 kardel NO_EVENT, 1031 1.1 kardel WSDCF_END, 1032 1.1 kardel NO_MESSAGE, 1033 1.1 kardel WSDCF_DATA, 1034 1.1 kardel WSDCF_ROOTDELAY, 1035 1.1 kardel WSDCF_BASEDELAY, 1036 1.1 kardel DCF_A_ID, 1037 1.1 kardel WSDCF_DESCRIPTION, 1038 1.1 kardel WSDCF_FORMAT, 1039 1.1 kardel DCF_TYPE, 1040 1.1 kardel WSDCF_MAXUNSYNC, 1041 1.1 kardel WSDCF_SPEED, 1042 1.1 kardel WSDCF_CFLAG, 1043 1.1 kardel WSDCF_IFLAG, 1044 1.1 kardel WSDCF_OFLAG, 1045 1.1 kardel WSDCF_LFLAG, 1046 1.1 kardel WSDCF_SAMPLES, 1047 1.1 kardel WSDCF_KEEP 1048 1.1 kardel }, 1049 1.1 kardel { /* mode 5 */ 1050 1.1 kardel RAWDCF_FLAGS, 1051 1.1 kardel NO_POLL, 1052 1.1 kardel RAWDCF_INIT, 1053 1.1 kardel NO_EVENT, 1054 1.1 kardel NO_END, 1055 1.1 kardel NO_MESSAGE, 1056 1.1 kardel NO_LCLDATA, 1057 1.1 kardel RAWDCF_ROOTDELAY, 1058 1.1 kardel CONRAD_BASEDELAY, 1059 1.1 kardel DCF_A_ID, 1060 1.1 kardel CONRAD_DESCRIPTION, 1061 1.1 kardel RAWDCF_FORMAT, 1062 1.1 kardel DCF_TYPE, 1063 1.1 kardel RAWDCF_MAXUNSYNC, 1064 1.1 kardel RAWDCF_SPEED, 1065 1.1 kardel RAWDCF_CFLAG, 1066 1.1 kardel RAWDCF_IFLAG, 1067 1.1 kardel RAWDCF_OFLAG, 1068 1.1 kardel RAWDCF_LFLAG, 1069 1.1 kardel RAWDCF_SAMPLES, 1070 1.1 kardel RAWDCF_KEEP 1071 1.1 kardel }, 1072 1.1 kardel { /* mode 6 */ 1073 1.1 kardel RAWDCF_FLAGS, 1074 1.1 kardel NO_POLL, 1075 1.1 kardel RAWDCF_INIT, 1076 1.1 kardel NO_EVENT, 1077 1.1 kardel NO_END, 1078 1.1 kardel NO_MESSAGE, 1079 1.1 kardel NO_LCLDATA, 1080 1.1 kardel RAWDCF_ROOTDELAY, 1081 1.1 kardel TIMEBRICK_BASEDELAY, 1082 1.1 kardel DCF_A_ID, 1083 1.1 kardel TIMEBRICK_DESCRIPTION, 1084 1.1 kardel RAWDCF_FORMAT, 1085 1.1 kardel DCF_TYPE, 1086 1.1 kardel RAWDCF_MAXUNSYNC, 1087 1.1 kardel RAWDCF_SPEED, 1088 1.1 kardel RAWDCF_CFLAG, 1089 1.1 kardel RAWDCF_IFLAG, 1090 1.1 kardel RAWDCF_OFLAG, 1091 1.1 kardel RAWDCF_LFLAG, 1092 1.1 kardel RAWDCF_SAMPLES, 1093 1.1 kardel RAWDCF_KEEP 1094 1.1 kardel }, 1095 1.1 kardel { /* mode 7 */ 1096 1.1 kardel MBG_FLAGS, 1097 1.1 kardel GPS16X_POLL, 1098 1.1 kardel GPS16X_INIT, 1099 1.1 kardel NO_EVENT, 1100 1.1 kardel GPS16X_END, 1101 1.1 kardel GPS16X_MESSAGE, 1102 1.1 kardel GPS16X_DATA, 1103 1.1 kardel GPS16X_ROOTDELAY, 1104 1.1 kardel GPS16X_BASEDELAY, 1105 1.1 kardel GPS16X_ID, 1106 1.1 kardel GPS16X_DESCRIPTION, 1107 1.1 kardel GPS16X_FORMAT, 1108 1.1 kardel GPS_TYPE, 1109 1.1 kardel GPS16X_MAXUNSYNC, 1110 1.1 kardel GPS16X_SPEED, 1111 1.1 kardel GPS16X_CFLAG, 1112 1.1 kardel GPS16X_IFLAG, 1113 1.1 kardel GPS16X_OFLAG, 1114 1.1 kardel GPS16X_LFLAG, 1115 1.1 kardel GPS16X_SAMPLES, 1116 1.1 kardel GPS16X_KEEP 1117 1.1 kardel }, 1118 1.1 kardel { /* mode 8 */ 1119 1.1 kardel RAWDCF_FLAGS, 1120 1.1 kardel NO_POLL, 1121 1.1 kardel NO_INIT, 1122 1.1 kardel NO_EVENT, 1123 1.1 kardel NO_END, 1124 1.1 kardel NO_MESSAGE, 1125 1.1 kardel NO_LCLDATA, 1126 1.1 kardel RAWDCF_ROOTDELAY, 1127 1.1 kardel IGELCLOCK_BASEDELAY, 1128 1.1 kardel DCF_A_ID, 1129 1.1 kardel IGELCLOCK_DESCRIPTION, 1130 1.1 kardel RAWDCF_FORMAT, 1131 1.1 kardel DCF_TYPE, 1132 1.1 kardel RAWDCF_MAXUNSYNC, 1133 1.1 kardel IGELCLOCK_SPEED, 1134 1.1 kardel IGELCLOCK_CFLAG, 1135 1.1 kardel RAWDCF_IFLAG, 1136 1.1 kardel RAWDCF_OFLAG, 1137 1.1 kardel RAWDCF_LFLAG, 1138 1.1 kardel RAWDCF_SAMPLES, 1139 1.1 kardel RAWDCF_KEEP 1140 1.1 kardel }, 1141 1.1 kardel { /* mode 9 */ 1142 1.1 kardel TRIMBLETAIP_FLAGS, 1143 1.1 kardel #if TRIM_POLLRATE /* DHD940515: Allow user config */ 1144 1.1 kardel NO_POLL, 1145 1.1 kardel #else 1146 1.1 kardel TRIMBLETAIP_POLL, 1147 1.1 kardel #endif 1148 1.1 kardel TRIMBLETAIP_INIT, 1149 1.1 kardel TRIMBLETAIP_EVENT, 1150 1.1 kardel TRIMBLETAIP_END, 1151 1.1 kardel NO_MESSAGE, 1152 1.1 kardel TRIMBLETAIP_DATA, 1153 1.1 kardel TRIMBLETAIP_ROOTDELAY, 1154 1.1 kardel TRIMBLETAIP_BASEDELAY, 1155 1.1 kardel TRIMBLETAIP_ID, 1156 1.1 kardel TRIMBLETAIP_DESCRIPTION, 1157 1.1 kardel TRIMBLETAIP_FORMAT, 1158 1.1 kardel GPS_TYPE, 1159 1.1 kardel TRIMBLETAIP_MAXUNSYNC, 1160 1.1 kardel TRIMBLETAIP_SPEED, 1161 1.1 kardel TRIMBLETAIP_CFLAG, 1162 1.1 kardel TRIMBLETAIP_IFLAG, 1163 1.1 kardel TRIMBLETAIP_OFLAG, 1164 1.1 kardel TRIMBLETAIP_LFLAG, 1165 1.1 kardel TRIMBLETAIP_SAMPLES, 1166 1.1 kardel TRIMBLETAIP_KEEP 1167 1.1 kardel }, 1168 1.1 kardel { /* mode 10 */ 1169 1.1 kardel TRIMBLETSIP_FLAGS, 1170 1.1 kardel #if TRIM_POLLRATE /* DHD940515: Allow user config */ 1171 1.1 kardel NO_POLL, 1172 1.1 kardel #else 1173 1.1 kardel TRIMBLETSIP_POLL, 1174 1.1 kardel #endif 1175 1.1 kardel TRIMBLETSIP_INIT, 1176 1.1 kardel TRIMBLETSIP_EVENT, 1177 1.1 kardel TRIMBLETSIP_END, 1178 1.1 kardel TRIMBLETSIP_MESSAGE, 1179 1.1 kardel TRIMBLETSIP_DATA, 1180 1.1 kardel TRIMBLETSIP_ROOTDELAY, 1181 1.1 kardel TRIMBLETSIP_BASEDELAY, 1182 1.1 kardel TRIMBLETSIP_ID, 1183 1.1 kardel TRIMBLETSIP_DESCRIPTION, 1184 1.1 kardel TRIMBLETSIP_FORMAT, 1185 1.1 kardel GPS_TYPE, 1186 1.1 kardel TRIMBLETSIP_MAXUNSYNC, 1187 1.1 kardel TRIMBLETSIP_SPEED, 1188 1.1 kardel TRIMBLETSIP_CFLAG, 1189 1.1 kardel TRIMBLETSIP_IFLAG, 1190 1.1 kardel TRIMBLETSIP_OFLAG, 1191 1.1 kardel TRIMBLETSIP_LFLAG, 1192 1.1 kardel TRIMBLETSIP_SAMPLES, 1193 1.1 kardel TRIMBLETSIP_KEEP 1194 1.1 kardel }, 1195 1.1 kardel { /* mode 11 */ 1196 1.1 kardel NO_CL_FLAGS, 1197 1.1 kardel RCC8000_POLL, 1198 1.1 kardel RCC8000_INIT, 1199 1.1 kardel NO_EVENT, 1200 1.1 kardel RCC8000_END, 1201 1.1 kardel NO_MESSAGE, 1202 1.1 kardel RCC8000_DATA, 1203 1.1 kardel RCC8000_ROOTDELAY, 1204 1.1 kardel RCC8000_BASEDELAY, 1205 1.1 kardel RCC8000_ID, 1206 1.1 kardel RCC8000_DESCRIPTION, 1207 1.1 kardel RCC8000_FORMAT, 1208 1.1 kardel DCF_TYPE, 1209 1.1 kardel RCC8000_MAXUNSYNC, 1210 1.1 kardel RCC8000_SPEED, 1211 1.1 kardel RCC8000_CFLAG, 1212 1.1 kardel RCC8000_IFLAG, 1213 1.1 kardel RCC8000_OFLAG, 1214 1.1 kardel RCC8000_LFLAG, 1215 1.1 kardel RCC8000_SAMPLES, 1216 1.1 kardel RCC8000_KEEP 1217 1.1 kardel }, 1218 1.1 kardel { /* mode 12 */ 1219 1.1 kardel HOPF6021_FLAGS, 1220 1.15 christos NO_POLL, 1221 1.1 kardel NO_INIT, 1222 1.1 kardel NO_EVENT, 1223 1.1 kardel NO_END, 1224 1.1 kardel NO_MESSAGE, 1225 1.1 kardel NO_LCLDATA, 1226 1.1 kardel HOPF6021_ROOTDELAY, 1227 1.1 kardel HOPF6021_BASEDELAY, 1228 1.1 kardel DCF_ID, 1229 1.1 kardel HOPF6021_DESCRIPTION, 1230 1.1 kardel HOPF6021_FORMAT, 1231 1.1 kardel DCF_TYPE, 1232 1.1 kardel HOPF6021_MAXUNSYNC, 1233 1.1 kardel HOPF6021_SPEED, 1234 1.1 kardel HOPF6021_CFLAG, 1235 1.1 kardel HOPF6021_IFLAG, 1236 1.1 kardel HOPF6021_OFLAG, 1237 1.1 kardel HOPF6021_LFLAG, 1238 1.1 kardel HOPF6021_SAMPLES, 1239 1.1 kardel HOPF6021_KEEP 1240 1.1 kardel }, 1241 1.1 kardel { /* mode 13 */ 1242 1.1 kardel COMPUTIME_FLAGS, 1243 1.1 kardel NO_POLL, 1244 1.1 kardel NO_INIT, 1245 1.1 kardel NO_EVENT, 1246 1.1 kardel NO_END, 1247 1.1 kardel NO_MESSAGE, 1248 1.1 kardel NO_LCLDATA, 1249 1.1 kardel COMPUTIME_ROOTDELAY, 1250 1.1 kardel COMPUTIME_BASEDELAY, 1251 1.1 kardel COMPUTIME_ID, 1252 1.1 kardel COMPUTIME_DESCRIPTION, 1253 1.1 kardel COMPUTIME_FORMAT, 1254 1.1 kardel COMPUTIME_TYPE, 1255 1.1 kardel COMPUTIME_MAXUNSYNC, 1256 1.1 kardel COMPUTIME_SPEED, 1257 1.1 kardel COMPUTIME_CFLAG, 1258 1.1 kardel COMPUTIME_IFLAG, 1259 1.1 kardel COMPUTIME_OFLAG, 1260 1.1 kardel COMPUTIME_LFLAG, 1261 1.1 kardel COMPUTIME_SAMPLES, 1262 1.1 kardel COMPUTIME_KEEP 1263 1.1 kardel }, 1264 1.1 kardel { /* mode 14 */ 1265 1.1 kardel RAWDCF_FLAGS, 1266 1.1 kardel NO_POLL, 1267 1.1 kardel RAWDCFDTRSET_INIT, 1268 1.1 kardel NO_EVENT, 1269 1.1 kardel NO_END, 1270 1.1 kardel NO_MESSAGE, 1271 1.1 kardel NO_LCLDATA, 1272 1.1 kardel RAWDCF_ROOTDELAY, 1273 1.1 kardel RAWDCF_BASEDELAY, 1274 1.1 kardel DCF_A_ID, 1275 1.1 kardel RAWDCFDTRSET_DESCRIPTION, 1276 1.1 kardel RAWDCF_FORMAT, 1277 1.1 kardel DCF_TYPE, 1278 1.1 kardel RAWDCF_MAXUNSYNC, 1279 1.1 kardel RAWDCF_SPEED, 1280 1.1 kardel RAWDCF_CFLAG, 1281 1.1 kardel RAWDCF_IFLAG, 1282 1.1 kardel RAWDCF_OFLAG, 1283 1.1 kardel RAWDCF_LFLAG, 1284 1.1 kardel RAWDCF_SAMPLES, 1285 1.1 kardel RAWDCF_KEEP 1286 1.1 kardel }, 1287 1.1 kardel { /* mode 15 */ 1288 1.1 kardel 0, /* operation flags (io modes) */ 1289 1.1 kardel NO_POLL, /* active poll routine */ 1290 1.1 kardel NO_INIT, /* active poll init routine */ 1291 1.1 kardel NO_EVENT, /* special event handling (e.g. reset clock) */ 1292 1.1 kardel NO_END, /* active poll end routine */ 1293 1.1 kardel NO_MESSAGE, /* process a lower layer message */ 1294 1.1 kardel NO_LCLDATA, /* local data area for "poll" mechanism */ 1295 1.1 kardel 0, /* rootdelay */ 1296 1.1 kardel 11.0 /* bits */ / 9600, /* current offset by which the RS232 1297 1.1 kardel time code is delayed from the actual time */ 1298 1.1 kardel DCF_ID, /* ID code */ 1299 1.1 kardel "WHARTON 400A Series clock", /* device name */ 1300 1.1 kardel "WHARTON 400A Series clock Output Format 1", /* fixed format */ 1301 1.1 kardel /* Must match a format-name in a libparse/clk_xxx.c file */ 1302 1.1 kardel DCF_TYPE, /* clock type (ntp control) */ 1303 1.1 kardel (1*60*60), /* time to trust oscillator after losing synch */ 1304 1.1 kardel B9600, /* terminal input & output baudrate */ 1305 1.1 kardel (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 1306 1.1 kardel 0, /* terminal input flags */ 1307 1.1 kardel 0, /* terminal output flags */ 1308 1.1 kardel 0, /* terminal local flags */ 1309 1.1 kardel 5, /* samples for median filter */ 1310 1.1 kardel 3, /* samples for median filter to keep */ 1311 1.1 kardel }, 1312 1.1 kardel { /* mode 16 - RAWDCF RTS set, DTR clr */ 1313 1.1 kardel RAWDCF_FLAGS, 1314 1.1 kardel NO_POLL, 1315 1.1 kardel RAWDCFDTRCLRRTSSET_INIT, 1316 1.1 kardel NO_EVENT, 1317 1.1 kardel NO_END, 1318 1.1 kardel NO_MESSAGE, 1319 1.1 kardel NO_LCLDATA, 1320 1.1 kardel RAWDCF_ROOTDELAY, 1321 1.1 kardel RAWDCF_BASEDELAY, 1322 1.1 kardel DCF_A_ID, 1323 1.1 kardel RAWDCFDTRCLRRTSSET_DESCRIPTION, 1324 1.1 kardel RAWDCF_FORMAT, 1325 1.1 kardel DCF_TYPE, 1326 1.1 kardel RAWDCF_MAXUNSYNC, 1327 1.1 kardel RAWDCF_SPEED, 1328 1.1 kardel RAWDCF_CFLAG, 1329 1.1 kardel RAWDCF_IFLAG, 1330 1.1 kardel RAWDCF_OFLAG, 1331 1.1 kardel RAWDCF_LFLAG, 1332 1.1 kardel RAWDCF_SAMPLES, 1333 1.1 kardel RAWDCF_KEEP 1334 1.1 kardel }, 1335 1.1 kardel { /* mode 17 */ 1336 1.1 kardel VARITEXT_FLAGS, 1337 1.1 kardel NO_POLL, 1338 1.1 kardel NO_INIT, 1339 1.1 kardel NO_EVENT, 1340 1.1 kardel NO_END, 1341 1.1 kardel NO_MESSAGE, 1342 1.1 kardel NO_LCLDATA, 1343 1.1 kardel VARITEXT_ROOTDELAY, 1344 1.1 kardel VARITEXT_BASEDELAY, 1345 1.1 kardel VARITEXT_ID, 1346 1.1 kardel VARITEXT_DESCRIPTION, 1347 1.1 kardel VARITEXT_FORMAT, 1348 1.1 kardel VARITEXT_TYPE, 1349 1.1 kardel VARITEXT_MAXUNSYNC, 1350 1.1 kardel VARITEXT_SPEED, 1351 1.1 kardel VARITEXT_CFLAG, 1352 1.1 kardel VARITEXT_IFLAG, 1353 1.1 kardel VARITEXT_OFLAG, 1354 1.1 kardel VARITEXT_LFLAG, 1355 1.1 kardel VARITEXT_SAMPLES, 1356 1.1 kardel VARITEXT_KEEP 1357 1.1 kardel }, 1358 1.1 kardel { /* mode 18 */ 1359 1.1 kardel MBG_FLAGS, 1360 1.1 kardel NO_POLL, 1361 1.1 kardel NO_INIT, 1362 1.1 kardel NO_EVENT, 1363 1.1 kardel GPS16X_END, 1364 1.1 kardel GPS16X_MESSAGE, 1365 1.1 kardel GPS16X_DATA, 1366 1.1 kardel GPS16X_ROOTDELAY, 1367 1.1 kardel GPS16X_BASEDELAY, 1368 1.1 kardel GPS16X_ID, 1369 1.1 kardel GPS16X_DESCRIPTION, 1370 1.1 kardel GPS16X_FORMAT, 1371 1.1 kardel GPS_TYPE, 1372 1.1 kardel GPS16X_MAXUNSYNC, 1373 1.1 kardel GPS16X_SPEED, 1374 1.1 kardel GPS16X_CFLAG, 1375 1.1 kardel GPS16X_IFLAG, 1376 1.1 kardel GPS16X_OFLAG, 1377 1.1 kardel GPS16X_LFLAG, 1378 1.1 kardel GPS16X_SAMPLES, 1379 1.1 kardel GPS16X_KEEP 1380 1.1 kardel }, 1381 1.1 kardel { /* mode 19 */ 1382 1.1 kardel RAWDCF_FLAGS, 1383 1.1 kardel NO_POLL, 1384 1.1 kardel RAWDCF_INIT, 1385 1.1 kardel NO_EVENT, 1386 1.1 kardel NO_END, 1387 1.1 kardel NO_MESSAGE, 1388 1.1 kardel NO_LCLDATA, 1389 1.1 kardel RAWDCF_ROOTDELAY, 1390 1.1 kardel GUDE_EMC_USB_V20_BASEDELAY, 1391 1.1 kardel DCF_A_ID, 1392 1.1 kardel GUDE_EMC_USB_V20_DESCRIPTION, 1393 1.1 kardel RAWDCF_FORMAT, 1394 1.1 kardel DCF_TYPE, 1395 1.1 kardel RAWDCF_MAXUNSYNC, 1396 1.1 kardel GUDE_EMC_USB_V20_SPEED, 1397 1.1 kardel RAWDCF_CFLAG, 1398 1.1 kardel RAWDCF_IFLAG, 1399 1.1 kardel RAWDCF_OFLAG, 1400 1.1 kardel RAWDCF_LFLAG, 1401 1.1 kardel RAWDCF_SAMPLES, 1402 1.1 kardel RAWDCF_KEEP 1403 1.1 kardel }, 1404 1.5 kardel { /* mode 20, like mode 14 but driven by 75 baud */ 1405 1.5 kardel RAWDCF_FLAGS, 1406 1.5 kardel NO_POLL, 1407 1.5 kardel RAWDCFDTRSET_INIT, 1408 1.5 kardel NO_EVENT, 1409 1.5 kardel NO_END, 1410 1.5 kardel NO_MESSAGE, 1411 1.5 kardel NO_LCLDATA, 1412 1.5 kardel RAWDCF_ROOTDELAY, 1413 1.5 kardel RAWDCF_BASEDELAY, 1414 1.5 kardel DCF_A_ID, 1415 1.5 kardel RAWDCFDTRSET75_DESCRIPTION, 1416 1.5 kardel RAWDCF_FORMAT, 1417 1.5 kardel DCF_TYPE, 1418 1.5 kardel RAWDCF_MAXUNSYNC, 1419 1.5 kardel B75, 1420 1.5 kardel RAWDCF_CFLAG, 1421 1.5 kardel RAWDCF_IFLAG, 1422 1.5 kardel RAWDCF_OFLAG, 1423 1.5 kardel RAWDCF_LFLAG, 1424 1.5 kardel RAWDCF_SAMPLES, 1425 1.5 kardel RAWDCF_KEEP 1426 1.5 kardel }, 1427 1.5 kardel { /* mode 21, like mode 16 but driven by 75 baud 1428 1.5 kardel - RAWDCF RTS set, DTR clr */ 1429 1.5 kardel RAWDCF_FLAGS, 1430 1.5 kardel NO_POLL, 1431 1.5 kardel RAWDCFDTRCLRRTSSET_INIT, 1432 1.5 kardel NO_EVENT, 1433 1.5 kardel NO_END, 1434 1.5 kardel NO_MESSAGE, 1435 1.5 kardel NO_LCLDATA, 1436 1.5 kardel RAWDCF_ROOTDELAY, 1437 1.5 kardel RAWDCF_BASEDELAY, 1438 1.5 kardel DCF_A_ID, 1439 1.5 kardel RAWDCFDTRCLRRTSSET75_DESCRIPTION, 1440 1.5 kardel RAWDCF_FORMAT, 1441 1.5 kardel DCF_TYPE, 1442 1.5 kardel RAWDCF_MAXUNSYNC, 1443 1.5 kardel B75, 1444 1.5 kardel RAWDCF_CFLAG, 1445 1.5 kardel RAWDCF_IFLAG, 1446 1.5 kardel RAWDCF_OFLAG, 1447 1.5 kardel RAWDCF_LFLAG, 1448 1.5 kardel RAWDCF_SAMPLES, 1449 1.5 kardel RAWDCF_KEEP 1450 1.5 kardel }, 1451 1.5 kardel { /* mode 22 - like 2 with POWERUP trust */ 1452 1.5 kardel MBG_FLAGS | PARSE_F_POWERUPTRUST, 1453 1.5 kardel NO_POLL, 1454 1.5 kardel NO_INIT, 1455 1.5 kardel NO_EVENT, 1456 1.5 kardel NO_END, 1457 1.5 kardel NO_MESSAGE, 1458 1.5 kardel NO_LCLDATA, 1459 1.5 kardel DCFUA31_ROOTDELAY, 1460 1.5 kardel DCFUA31_BASEDELAY, 1461 1.5 kardel DCF_A_ID, 1462 1.5 kardel DCFUA31_DESCRIPTION, 1463 1.5 kardel DCFUA31_FORMAT, 1464 1.5 kardel DCF_TYPE, 1465 1.5 kardel DCFUA31_MAXUNSYNC, 1466 1.5 kardel DCFUA31_SPEED, 1467 1.5 kardel DCFUA31_CFLAG, 1468 1.5 kardel DCFUA31_IFLAG, 1469 1.5 kardel DCFUA31_OFLAG, 1470 1.5 kardel DCFUA31_LFLAG, 1471 1.5 kardel DCFUA31_SAMPLES, 1472 1.5 kardel DCFUA31_KEEP 1473 1.5 kardel }, 1474 1.5 kardel { /* mode 23 - like 7 with POWERUP trust */ 1475 1.5 kardel MBG_FLAGS | PARSE_F_POWERUPTRUST, 1476 1.5 kardel GPS16X_POLL, 1477 1.5 kardel GPS16X_INIT, 1478 1.5 kardel NO_EVENT, 1479 1.5 kardel GPS16X_END, 1480 1.5 kardel GPS16X_MESSAGE, 1481 1.5 kardel GPS16X_DATA, 1482 1.5 kardel GPS16X_ROOTDELAY, 1483 1.5 kardel GPS16X_BASEDELAY, 1484 1.5 kardel GPS16X_ID, 1485 1.5 kardel GPS16X_DESCRIPTION, 1486 1.5 kardel GPS16X_FORMAT, 1487 1.5 kardel GPS_TYPE, 1488 1.5 kardel GPS16X_MAXUNSYNC, 1489 1.5 kardel GPS16X_SPEED, 1490 1.5 kardel GPS16X_CFLAG, 1491 1.5 kardel GPS16X_IFLAG, 1492 1.5 kardel GPS16X_OFLAG, 1493 1.5 kardel GPS16X_LFLAG, 1494 1.5 kardel GPS16X_SAMPLES, 1495 1.5 kardel GPS16X_KEEP 1496 1.5 kardel }, 1497 1.10 christos { /* mode 24 */ 1498 1.10 christos SEL240X_FLAGS, 1499 1.10 christos SEL240X_POLL, 1500 1.10 christos SEL240X_INIT, 1501 1.10 christos NO_EVENT, 1502 1.10 christos SEL240X_END, 1503 1.10 christos NO_MESSAGE, 1504 1.10 christos SEL240X_DATA, 1505 1.10 christos SEL240X_ROOTDELAY, 1506 1.10 christos SEL240X_BASEDELAY, 1507 1.10 christos SEL240X_ID, 1508 1.10 christos SEL240X_DESCRIPTION, 1509 1.10 christos SEL240X_FORMAT, 1510 1.10 christos GPS_TYPE, 1511 1.10 christos SEL240X_MAXUNSYNC, 1512 1.10 christos SEL240X_SPEED, 1513 1.10 christos SEL240X_CFLAG, 1514 1.10 christos SEL240X_IFLAG, 1515 1.10 christos SEL240X_OFLAG, 1516 1.10 christos SEL240X_LFLAG, 1517 1.10 christos SEL240X_SAMPLES, 1518 1.10 christos SEL240X_KEEP 1519 1.10 christos }, 1520 1.1 kardel }; 1521 1.1 kardel 1522 1.1 kardel static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 1523 1.1 kardel 1524 1.1 kardel #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 1525 1.1 kardel #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 1526 1.1 kardel #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 1527 1.1 kardel #define CLK_PPS(x) (((x)->ttl) & 0x80) 1528 1.1 kardel 1529 1.1 kardel /* 1530 1.1 kardel * Other constant stuff 1531 1.1 kardel */ 1532 1.1 kardel #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 1533 1.1 kardel 1534 1.1 kardel #define PARSESTATISTICS (60*60) /* output state statistics every hour */ 1535 1.1 kardel 1536 1.1 kardel static int notice = 0; 1537 1.1 kardel 1538 1.1 kardel #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 1539 1.1 kardel 1540 1.1 kardel static void parse_event (struct parseunit *, int); 1541 1.1 kardel static void parse_process (struct parseunit *, parsetime_t *); 1542 1.1 kardel static void clear_err (struct parseunit *, u_long); 1543 1.1 kardel static int list_err (struct parseunit *, u_long); 1544 1.1 kardel static char * l_mktime (u_long); 1545 1.1 kardel 1546 1.1 kardel /**=========================================================================== 1547 1.1 kardel ** implementation error message regression module 1548 1.1 kardel **/ 1549 1.1 kardel static void 1550 1.1 kardel clear_err( 1551 1.1 kardel struct parseunit *parse, 1552 1.1 kardel u_long lstate 1553 1.1 kardel ) 1554 1.1 kardel { 1555 1.1 kardel if (lstate == ERR_ALL) 1556 1.1 kardel { 1557 1.3 christos size_t i; 1558 1.1 kardel 1559 1.1 kardel for (i = 0; i < ERR_CNT; i++) 1560 1.1 kardel { 1561 1.1 kardel parse->errors[i].err_stage = err_tbl[i]; 1562 1.1 kardel parse->errors[i].err_cnt = 0; 1563 1.1 kardel parse->errors[i].err_last = 0; 1564 1.1 kardel parse->errors[i].err_started = 0; 1565 1.1 kardel parse->errors[i].err_suppressed = 0; 1566 1.1 kardel } 1567 1.1 kardel } 1568 1.1 kardel else 1569 1.1 kardel { 1570 1.1 kardel parse->errors[lstate].err_stage = err_tbl[lstate]; 1571 1.1 kardel parse->errors[lstate].err_cnt = 0; 1572 1.1 kardel parse->errors[lstate].err_last = 0; 1573 1.1 kardel parse->errors[lstate].err_started = 0; 1574 1.1 kardel parse->errors[lstate].err_suppressed = 0; 1575 1.1 kardel } 1576 1.1 kardel } 1577 1.1 kardel 1578 1.1 kardel static int 1579 1.1 kardel list_err( 1580 1.1 kardel struct parseunit *parse, 1581 1.1 kardel u_long lstate 1582 1.1 kardel ) 1583 1.1 kardel { 1584 1.1 kardel int do_it; 1585 1.1 kardel struct errorinfo *err = &parse->errors[lstate]; 1586 1.1 kardel 1587 1.1 kardel if (err->err_started == 0) 1588 1.1 kardel { 1589 1.1 kardel err->err_started = current_time; 1590 1.1 kardel } 1591 1.1 kardel 1592 1.1 kardel do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 1593 1.1 kardel 1594 1.1 kardel if (do_it) 1595 1.1 kardel err->err_cnt++; 1596 1.15 christos 1597 1.1 kardel if (err->err_stage->err_count && 1598 1.1 kardel (err->err_cnt >= err->err_stage->err_count)) 1599 1.1 kardel { 1600 1.1 kardel err->err_stage++; 1601 1.1 kardel err->err_cnt = 0; 1602 1.1 kardel } 1603 1.1 kardel 1604 1.1 kardel if (!err->err_cnt && do_it) 1605 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 1606 1.1 kardel CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 1607 1.1 kardel 1608 1.1 kardel if (!do_it) 1609 1.1 kardel err->err_suppressed++; 1610 1.1 kardel else 1611 1.1 kardel err->err_last = current_time; 1612 1.1 kardel 1613 1.1 kardel if (do_it && err->err_suppressed) 1614 1.1 kardel { 1615 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 1616 1.1 kardel CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 1617 1.1 kardel l_mktime(current_time - err->err_started)); 1618 1.1 kardel err->err_suppressed = 0; 1619 1.1 kardel } 1620 1.15 christos 1621 1.1 kardel return do_it; 1622 1.1 kardel } 1623 1.1 kardel 1624 1.1 kardel /*-------------------------------------------------- 1625 1.1 kardel * mkreadable - make a printable ascii string (without 1626 1.1 kardel * embedded quotes so that the ntpq protocol isn't 1627 1.1 kardel * fooled 1628 1.1 kardel */ 1629 1.1 kardel #ifndef isprint 1630 1.1 kardel #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 1631 1.1 kardel #endif 1632 1.1 kardel 1633 1.1 kardel static char * 1634 1.1 kardel mkreadable( 1635 1.1 kardel char *buffer, 1636 1.18 christos size_t blen, 1637 1.1 kardel const char *src, 1638 1.18 christos size_t srclen, 1639 1.1 kardel int hex 1640 1.1 kardel ) 1641 1.1 kardel { 1642 1.10 christos static const char ellipsis[] = "..."; 1643 1.1 kardel char *b = buffer; 1644 1.5 kardel char *endb = NULL; 1645 1.1 kardel 1646 1.1 kardel if (blen < 4) 1647 1.5 kardel return NULL; /* don't bother with mini buffers */ 1648 1.1 kardel 1649 1.10 christos endb = buffer + blen - sizeof(ellipsis); 1650 1.1 kardel 1651 1.1 kardel blen--; /* account for '\0' */ 1652 1.1 kardel 1653 1.1 kardel while (blen && srclen--) 1654 1.1 kardel { 1655 1.1 kardel if (!hex && /* no binary only */ 1656 1.1 kardel (*src != '\\') && /* no plain \ */ 1657 1.1 kardel (*src != '"') && /* no " */ 1658 1.2 christos isprint((unsigned char)*src)) /* only printables */ 1659 1.1 kardel { /* they are easy... */ 1660 1.1 kardel *buffer++ = *src++; 1661 1.1 kardel blen--; 1662 1.1 kardel } 1663 1.1 kardel else 1664 1.1 kardel { 1665 1.1 kardel if (blen < 4) 1666 1.1 kardel { 1667 1.1 kardel while (blen--) 1668 1.1 kardel { 1669 1.1 kardel *buffer++ = '.'; 1670 1.1 kardel } 1671 1.1 kardel *buffer = '\0'; 1672 1.1 kardel return b; 1673 1.1 kardel } 1674 1.1 kardel else 1675 1.1 kardel { 1676 1.1 kardel if (*src == '\\') 1677 1.1 kardel { 1678 1.10 christos memcpy(buffer, "\\\\", 2); 1679 1.1 kardel buffer += 2; 1680 1.1 kardel blen -= 2; 1681 1.1 kardel src++; 1682 1.1 kardel } 1683 1.1 kardel else 1684 1.1 kardel { 1685 1.5 kardel snprintf(buffer, blen, "\\x%02x", *src++); 1686 1.1 kardel blen -= 4; 1687 1.1 kardel buffer += 4; 1688 1.1 kardel } 1689 1.1 kardel } 1690 1.1 kardel } 1691 1.1 kardel if (srclen && !blen && endb) /* overflow - set last chars to ... */ 1692 1.10 christos memcpy(endb, ellipsis, sizeof(ellipsis)); 1693 1.1 kardel } 1694 1.1 kardel 1695 1.1 kardel *buffer = '\0'; 1696 1.1 kardel return b; 1697 1.1 kardel } 1698 1.1 kardel 1699 1.1 kardel 1700 1.1 kardel /*-------------------------------------------------- 1701 1.1 kardel * mkascii - make a printable ascii string 1702 1.1 kardel * assumes (unless defined better) 7-bit ASCII 1703 1.1 kardel */ 1704 1.1 kardel static char * 1705 1.1 kardel mkascii( 1706 1.1 kardel char *buffer, 1707 1.1 kardel long blen, 1708 1.1 kardel const char *src, 1709 1.1 kardel u_long srclen 1710 1.1 kardel ) 1711 1.1 kardel { 1712 1.1 kardel return mkreadable(buffer, blen, src, srclen, 0); 1713 1.1 kardel } 1714 1.1 kardel 1715 1.1 kardel /**=========================================================================== 1716 1.1 kardel ** implementation of i/o handling methods 1717 1.1 kardel ** (all STREAM, partial STREAM, user level) 1718 1.1 kardel **/ 1719 1.1 kardel 1720 1.1 kardel /* 1721 1.1 kardel * define possible io handling methods 1722 1.1 kardel */ 1723 1.1 kardel #ifdef STREAM 1724 1.1 kardel static int ppsclock_init (struct parseunit *); 1725 1.1 kardel static int stream_init (struct parseunit *); 1726 1.1 kardel static void stream_end (struct parseunit *); 1727 1.1 kardel static int stream_enable (struct parseunit *); 1728 1.1 kardel static int stream_disable (struct parseunit *); 1729 1.1 kardel static int stream_setcs (struct parseunit *, parsectl_t *); 1730 1.1 kardel static int stream_getfmt (struct parseunit *, parsectl_t *); 1731 1.1 kardel static int stream_setfmt (struct parseunit *, parsectl_t *); 1732 1.1 kardel static int stream_timecode (struct parseunit *, parsectl_t *); 1733 1.1 kardel static void stream_receive (struct recvbuf *); 1734 1.1 kardel #endif 1735 1.15 christos 1736 1.1 kardel static int local_init (struct parseunit *); 1737 1.1 kardel static void local_end (struct parseunit *); 1738 1.1 kardel static int local_nop (struct parseunit *); 1739 1.1 kardel static int local_setcs (struct parseunit *, parsectl_t *); 1740 1.1 kardel static int local_getfmt (struct parseunit *, parsectl_t *); 1741 1.1 kardel static int local_setfmt (struct parseunit *, parsectl_t *); 1742 1.1 kardel static int local_timecode (struct parseunit *, parsectl_t *); 1743 1.1 kardel static void local_receive (struct recvbuf *); 1744 1.1 kardel static int local_input (struct recvbuf *); 1745 1.1 kardel 1746 1.1 kardel static bind_t io_bindings[] = 1747 1.1 kardel { 1748 1.1 kardel #ifdef STREAM 1749 1.1 kardel { 1750 1.1 kardel "parse STREAM", 1751 1.1 kardel stream_init, 1752 1.1 kardel stream_end, 1753 1.1 kardel stream_setcs, 1754 1.1 kardel stream_disable, 1755 1.1 kardel stream_enable, 1756 1.1 kardel stream_getfmt, 1757 1.1 kardel stream_setfmt, 1758 1.1 kardel stream_timecode, 1759 1.1 kardel stream_receive, 1760 1.1 kardel 0, 1761 1.1 kardel }, 1762 1.1 kardel { 1763 1.1 kardel "ppsclock STREAM", 1764 1.1 kardel ppsclock_init, 1765 1.1 kardel local_end, 1766 1.1 kardel local_setcs, 1767 1.1 kardel local_nop, 1768 1.1 kardel local_nop, 1769 1.1 kardel local_getfmt, 1770 1.1 kardel local_setfmt, 1771 1.1 kardel local_timecode, 1772 1.1 kardel local_receive, 1773 1.1 kardel local_input, 1774 1.1 kardel }, 1775 1.1 kardel #endif 1776 1.1 kardel { 1777 1.1 kardel "normal", 1778 1.1 kardel local_init, 1779 1.1 kardel local_end, 1780 1.1 kardel local_setcs, 1781 1.1 kardel local_nop, 1782 1.1 kardel local_nop, 1783 1.1 kardel local_getfmt, 1784 1.1 kardel local_setfmt, 1785 1.1 kardel local_timecode, 1786 1.1 kardel local_receive, 1787 1.1 kardel local_input, 1788 1.1 kardel }, 1789 1.1 kardel { 1790 1.1 kardel (char *)0, 1791 1.3 christos NULL, 1792 1.3 christos NULL, 1793 1.3 christos NULL, 1794 1.3 christos NULL, 1795 1.3 christos NULL, 1796 1.3 christos NULL, 1797 1.3 christos NULL, 1798 1.3 christos NULL, 1799 1.3 christos NULL, 1800 1.3 christos NULL, 1801 1.1 kardel } 1802 1.1 kardel }; 1803 1.1 kardel 1804 1.1 kardel #ifdef STREAM 1805 1.1 kardel 1806 1.1 kardel /*-------------------------------------------------- 1807 1.1 kardel * ppsclock STREAM init 1808 1.1 kardel */ 1809 1.1 kardel static int 1810 1.1 kardel ppsclock_init( 1811 1.1 kardel struct parseunit *parse 1812 1.1 kardel ) 1813 1.1 kardel { 1814 1.1 kardel static char m1[] = "ppsclocd"; 1815 1.1 kardel static char m2[] = "ppsclock"; 1816 1.15 christos 1817 1.1 kardel /* 1818 1.1 kardel * now push the parse streams module 1819 1.1 kardel * it will ensure exclusive access to the device 1820 1.1 kardel */ 1821 1.1 kardel if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 && 1822 1.1 kardel ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1) 1823 1.1 kardel { 1824 1.1 kardel if (errno != EINVAL) 1825 1.1 kardel { 1826 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 1827 1.1 kardel CLK_UNIT(parse->peer)); 1828 1.1 kardel } 1829 1.1 kardel return 0; 1830 1.1 kardel } 1831 1.1 kardel if (!local_init(parse)) 1832 1.1 kardel { 1833 1.1 kardel (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0); 1834 1.1 kardel return 0; 1835 1.1 kardel } 1836 1.1 kardel 1837 1.1 kardel parse->flags |= PARSE_PPSCLOCK; 1838 1.1 kardel return 1; 1839 1.1 kardel } 1840 1.1 kardel 1841 1.1 kardel /*-------------------------------------------------- 1842 1.1 kardel * parse STREAM init 1843 1.1 kardel */ 1844 1.1 kardel static int 1845 1.1 kardel stream_init( 1846 1.1 kardel struct parseunit *parse 1847 1.1 kardel ) 1848 1.1 kardel { 1849 1.1 kardel static char m1[] = "parse"; 1850 1.1 kardel /* 1851 1.1 kardel * now push the parse streams module 1852 1.1 kardel * to test whether it is there (neat interface 8-( ) 1853 1.1 kardel */ 1854 1.1 kardel if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1855 1.1 kardel { 1856 1.1 kardel if (errno != EINVAL) /* accept non-existence */ 1857 1.1 kardel { 1858 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1859 1.1 kardel } 1860 1.1 kardel return 0; 1861 1.1 kardel } 1862 1.1 kardel else 1863 1.1 kardel { 1864 1.1 kardel while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1865 1.1 kardel /* empty loop */; 1866 1.1 kardel 1867 1.1 kardel /* 1868 1.1 kardel * now push it a second time after we have removed all 1869 1.1 kardel * module garbage 1870 1.1 kardel */ 1871 1.1 kardel if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 1872 1.1 kardel { 1873 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 1874 1.1 kardel return 0; 1875 1.1 kardel } 1876 1.1 kardel else 1877 1.1 kardel { 1878 1.1 kardel return 1; 1879 1.1 kardel } 1880 1.1 kardel } 1881 1.1 kardel } 1882 1.1 kardel 1883 1.1 kardel /*-------------------------------------------------- 1884 1.1 kardel * parse STREAM end 1885 1.1 kardel */ 1886 1.1 kardel static void 1887 1.1 kardel stream_end( 1888 1.1 kardel struct parseunit *parse 1889 1.1 kardel ) 1890 1.1 kardel { 1891 1.1 kardel while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 1892 1.1 kardel /* empty loop */; 1893 1.1 kardel } 1894 1.1 kardel 1895 1.1 kardel /*-------------------------------------------------- 1896 1.1 kardel * STREAM setcs 1897 1.1 kardel */ 1898 1.1 kardel static int 1899 1.1 kardel stream_setcs( 1900 1.1 kardel struct parseunit *parse, 1901 1.1 kardel parsectl_t *tcl 1902 1.1 kardel ) 1903 1.1 kardel { 1904 1.1 kardel struct strioctl strioc; 1905 1.15 christos 1906 1.1 kardel strioc.ic_cmd = PARSEIOC_SETCS; 1907 1.1 kardel strioc.ic_timout = 0; 1908 1.1 kardel strioc.ic_dp = (char *)tcl; 1909 1.1 kardel strioc.ic_len = sizeof (*tcl); 1910 1.1 kardel 1911 1.1 kardel if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1912 1.1 kardel { 1913 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 1914 1.1 kardel return 0; 1915 1.1 kardel } 1916 1.1 kardel return 1; 1917 1.1 kardel } 1918 1.1 kardel 1919 1.1 kardel /*-------------------------------------------------- 1920 1.1 kardel * STREAM enable 1921 1.1 kardel */ 1922 1.1 kardel static int 1923 1.1 kardel stream_enable( 1924 1.1 kardel struct parseunit *parse 1925 1.1 kardel ) 1926 1.1 kardel { 1927 1.1 kardel struct strioctl strioc; 1928 1.15 christos 1929 1.1 kardel strioc.ic_cmd = PARSEIOC_ENABLE; 1930 1.1 kardel strioc.ic_timout = 0; 1931 1.1 kardel strioc.ic_dp = (char *)0; 1932 1.1 kardel strioc.ic_len = 0; 1933 1.1 kardel 1934 1.1 kardel if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1935 1.1 kardel { 1936 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 1937 1.1 kardel return 0; 1938 1.1 kardel } 1939 1.1 kardel parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 1940 1.1 kardel return 1; 1941 1.1 kardel } 1942 1.1 kardel 1943 1.1 kardel /*-------------------------------------------------- 1944 1.1 kardel * STREAM disable 1945 1.1 kardel */ 1946 1.1 kardel static int 1947 1.1 kardel stream_disable( 1948 1.1 kardel struct parseunit *parse 1949 1.1 kardel ) 1950 1.1 kardel { 1951 1.1 kardel struct strioctl strioc; 1952 1.15 christos 1953 1.1 kardel strioc.ic_cmd = PARSEIOC_DISABLE; 1954 1.1 kardel strioc.ic_timout = 0; 1955 1.1 kardel strioc.ic_dp = (char *)0; 1956 1.1 kardel strioc.ic_len = 0; 1957 1.1 kardel 1958 1.1 kardel if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1959 1.1 kardel { 1960 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 1961 1.1 kardel return 0; 1962 1.1 kardel } 1963 1.1 kardel parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 1964 1.1 kardel return 1; 1965 1.1 kardel } 1966 1.1 kardel 1967 1.1 kardel /*-------------------------------------------------- 1968 1.1 kardel * STREAM getfmt 1969 1.1 kardel */ 1970 1.1 kardel static int 1971 1.1 kardel stream_getfmt( 1972 1.1 kardel struct parseunit *parse, 1973 1.1 kardel parsectl_t *tcl 1974 1.1 kardel ) 1975 1.1 kardel { 1976 1.1 kardel struct strioctl strioc; 1977 1.15 christos 1978 1.1 kardel strioc.ic_cmd = PARSEIOC_GETFMT; 1979 1.1 kardel strioc.ic_timout = 0; 1980 1.1 kardel strioc.ic_dp = (char *)tcl; 1981 1.1 kardel strioc.ic_len = sizeof (*tcl); 1982 1.1 kardel if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 1983 1.1 kardel { 1984 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 1985 1.1 kardel return 0; 1986 1.1 kardel } 1987 1.1 kardel return 1; 1988 1.1 kardel } 1989 1.1 kardel 1990 1.1 kardel /*-------------------------------------------------- 1991 1.1 kardel * STREAM setfmt 1992 1.1 kardel */ 1993 1.1 kardel static int 1994 1.1 kardel stream_setfmt( 1995 1.1 kardel struct parseunit *parse, 1996 1.1 kardel parsectl_t *tcl 1997 1.1 kardel ) 1998 1.1 kardel { 1999 1.1 kardel struct strioctl strioc; 2000 1.15 christos 2001 1.1 kardel strioc.ic_cmd = PARSEIOC_SETFMT; 2002 1.1 kardel strioc.ic_timout = 0; 2003 1.1 kardel strioc.ic_dp = (char *)tcl; 2004 1.1 kardel strioc.ic_len = sizeof (*tcl); 2005 1.1 kardel 2006 1.1 kardel if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 2007 1.1 kardel { 2008 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 2009 1.1 kardel return 0; 2010 1.1 kardel } 2011 1.1 kardel return 1; 2012 1.1 kardel } 2013 1.1 kardel 2014 1.1 kardel 2015 1.1 kardel /*-------------------------------------------------- 2016 1.1 kardel * STREAM timecode 2017 1.1 kardel */ 2018 1.1 kardel static int 2019 1.1 kardel stream_timecode( 2020 1.1 kardel struct parseunit *parse, 2021 1.1 kardel parsectl_t *tcl 2022 1.1 kardel ) 2023 1.1 kardel { 2024 1.1 kardel struct strioctl strioc; 2025 1.15 christos 2026 1.1 kardel strioc.ic_cmd = PARSEIOC_TIMECODE; 2027 1.1 kardel strioc.ic_timout = 0; 2028 1.1 kardel strioc.ic_dp = (char *)tcl; 2029 1.1 kardel strioc.ic_len = sizeof (*tcl); 2030 1.15 christos 2031 1.1 kardel if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 2032 1.1 kardel { 2033 1.1 kardel ERR(ERR_INTERNAL) 2034 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 2035 1.1 kardel return 0; 2036 1.1 kardel } 2037 1.1 kardel clear_err(parse, ERR_INTERNAL); 2038 1.1 kardel return 1; 2039 1.1 kardel } 2040 1.1 kardel 2041 1.1 kardel /*-------------------------------------------------- 2042 1.1 kardel * STREAM receive 2043 1.1 kardel */ 2044 1.1 kardel static void 2045 1.1 kardel stream_receive( 2046 1.1 kardel struct recvbuf *rbufp 2047 1.1 kardel ) 2048 1.1 kardel { 2049 1.10 christos struct parseunit * parse; 2050 1.1 kardel parsetime_t parsetime; 2051 1.1 kardel 2052 1.10 christos parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 2053 1.1 kardel if (!parse->peer) 2054 1.1 kardel return; 2055 1.1 kardel 2056 1.1 kardel if (rbufp->recv_length != sizeof(parsetime_t)) 2057 1.1 kardel { 2058 1.1 kardel ERR(ERR_BADIO) 2059 1.1 kardel msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 2060 1.1 kardel CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 2061 1.1 kardel parse_event(parse, CEVNT_BADREPLY); 2062 1.1 kardel return; 2063 1.1 kardel } 2064 1.1 kardel clear_err(parse, ERR_BADIO); 2065 1.15 christos 2066 1.1 kardel memmove((caddr_t)&parsetime, 2067 1.1 kardel (caddr_t)rbufp->recv_buffer, 2068 1.1 kardel sizeof(parsetime_t)); 2069 1.1 kardel 2070 1.1 kardel #ifdef DEBUG 2071 1.1 kardel if (debug > 3) 2072 1.1 kardel { 2073 1.1 kardel printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 2074 1.1 kardel CLK_UNIT(parse->peer), 2075 1.1 kardel (unsigned int)parsetime.parse_status, 2076 1.1 kardel (unsigned int)parsetime.parse_state, 2077 1.1 kardel (unsigned long)parsetime.parse_time.tv.tv_sec, 2078 1.1 kardel (unsigned long)parsetime.parse_time.tv.tv_usec, 2079 1.1 kardel (unsigned long)parsetime.parse_stime.tv.tv_sec, 2080 1.1 kardel (unsigned long)parsetime.parse_stime.tv.tv_usec, 2081 1.1 kardel (unsigned long)parsetime.parse_ptime.tv.tv_sec, 2082 1.1 kardel (unsigned long)parsetime.parse_ptime.tv.tv_usec); 2083 1.1 kardel } 2084 1.1 kardel #endif 2085 1.1 kardel 2086 1.1 kardel /* 2087 1.1 kardel * switch time stamp world - be sure to normalize small usec field 2088 1.1 kardel * errors. 2089 1.1 kardel */ 2090 1.1 kardel 2091 1.10 christos parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv); 2092 1.1 kardel 2093 1.1 kardel if (PARSE_TIMECODE(parsetime.parse_state)) 2094 1.1 kardel { 2095 1.10 christos parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv); 2096 1.1 kardel } 2097 1.1 kardel 2098 1.1 kardel if (PARSE_PPS(parsetime.parse_state)) 2099 1.10 christos { 2100 1.10 christos parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv); 2101 1.10 christos } 2102 1.1 kardel 2103 1.1 kardel parse_process(parse, &parsetime); 2104 1.1 kardel } 2105 1.1 kardel #endif 2106 1.1 kardel 2107 1.1 kardel /*-------------------------------------------------- 2108 1.1 kardel * local init 2109 1.1 kardel */ 2110 1.1 kardel static int 2111 1.1 kardel local_init( 2112 1.1 kardel struct parseunit *parse 2113 1.1 kardel ) 2114 1.1 kardel { 2115 1.1 kardel return parse_ioinit(&parse->parseio); 2116 1.1 kardel } 2117 1.1 kardel 2118 1.1 kardel /*-------------------------------------------------- 2119 1.1 kardel * local end 2120 1.1 kardel */ 2121 1.1 kardel static void 2122 1.1 kardel local_end( 2123 1.1 kardel struct parseunit *parse 2124 1.1 kardel ) 2125 1.1 kardel { 2126 1.1 kardel parse_ioend(&parse->parseio); 2127 1.1 kardel } 2128 1.1 kardel 2129 1.1 kardel 2130 1.1 kardel /*-------------------------------------------------- 2131 1.1 kardel * local nop 2132 1.1 kardel */ 2133 1.1 kardel static int 2134 1.1 kardel local_nop( 2135 1.1 kardel struct parseunit *parse 2136 1.1 kardel ) 2137 1.1 kardel { 2138 1.1 kardel return 1; 2139 1.1 kardel } 2140 1.1 kardel 2141 1.1 kardel /*-------------------------------------------------- 2142 1.1 kardel * local setcs 2143 1.1 kardel */ 2144 1.1 kardel static int 2145 1.1 kardel local_setcs( 2146 1.1 kardel struct parseunit *parse, 2147 1.1 kardel parsectl_t *tcl 2148 1.1 kardel ) 2149 1.1 kardel { 2150 1.1 kardel return parse_setcs(tcl, &parse->parseio); 2151 1.1 kardel } 2152 1.1 kardel 2153 1.1 kardel /*-------------------------------------------------- 2154 1.1 kardel * local getfmt 2155 1.1 kardel */ 2156 1.1 kardel static int 2157 1.1 kardel local_getfmt( 2158 1.1 kardel struct parseunit *parse, 2159 1.1 kardel parsectl_t *tcl 2160 1.1 kardel ) 2161 1.1 kardel { 2162 1.1 kardel return parse_getfmt(tcl, &parse->parseio); 2163 1.1 kardel } 2164 1.1 kardel 2165 1.1 kardel /*-------------------------------------------------- 2166 1.1 kardel * local setfmt 2167 1.1 kardel */ 2168 1.1 kardel static int 2169 1.1 kardel local_setfmt( 2170 1.1 kardel struct parseunit *parse, 2171 1.1 kardel parsectl_t *tcl 2172 1.1 kardel ) 2173 1.1 kardel { 2174 1.1 kardel return parse_setfmt(tcl, &parse->parseio); 2175 1.1 kardel } 2176 1.1 kardel 2177 1.1 kardel /*-------------------------------------------------- 2178 1.1 kardel * local timecode 2179 1.1 kardel */ 2180 1.1 kardel static int 2181 1.1 kardel local_timecode( 2182 1.1 kardel struct parseunit *parse, 2183 1.1 kardel parsectl_t *tcl 2184 1.1 kardel ) 2185 1.1 kardel { 2186 1.1 kardel return parse_timecode(tcl, &parse->parseio); 2187 1.1 kardel } 2188 1.1 kardel 2189 1.1 kardel 2190 1.1 kardel /*-------------------------------------------------- 2191 1.1 kardel * local input 2192 1.1 kardel */ 2193 1.1 kardel static int 2194 1.1 kardel local_input( 2195 1.1 kardel struct recvbuf *rbufp 2196 1.1 kardel ) 2197 1.1 kardel { 2198 1.10 christos struct parseunit * parse; 2199 1.10 christos 2200 1.1 kardel int count; 2201 1.1 kardel unsigned char *s; 2202 1.1 kardel timestamp_t ts; 2203 1.1 kardel 2204 1.10 christos parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 2205 1.1 kardel if (!parse->peer) 2206 1.1 kardel return 0; 2207 1.1 kardel 2208 1.1 kardel /* 2209 1.1 kardel * eat all characters, parsing then and feeding complete samples 2210 1.1 kardel */ 2211 1.1 kardel count = rbufp->recv_length; 2212 1.1 kardel s = (unsigned char *)rbufp->recv_buffer; 2213 1.1 kardel ts.fp = rbufp->recv_time; 2214 1.1 kardel 2215 1.1 kardel while (count--) 2216 1.1 kardel { 2217 1.1 kardel if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 2218 1.1 kardel { 2219 1.1 kardel struct recvbuf *buf; 2220 1.1 kardel 2221 1.1 kardel /* 2222 1.1 kardel * got something good to eat 2223 1.1 kardel */ 2224 1.1 kardel if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 2225 1.1 kardel { 2226 1.1 kardel #ifdef HAVE_PPSAPI 2227 1.1 kardel if (parse->flags & PARSE_PPSCLOCK) 2228 1.1 kardel { 2229 1.1 kardel struct timespec pps_timeout; 2230 1.1 kardel pps_info_t pps_info; 2231 1.15 christos 2232 1.1 kardel pps_timeout.tv_sec = 0; 2233 1.1 kardel pps_timeout.tv_nsec = 0; 2234 1.1 kardel 2235 1.1 kardel if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info, 2236 1.1 kardel &pps_timeout) == 0) 2237 1.1 kardel { 2238 1.1 kardel if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial) 2239 1.1 kardel { 2240 1.1 kardel double dtemp; 2241 1.1 kardel 2242 1.1 kardel struct timespec pts; 2243 1.1 kardel /* 2244 1.1 kardel * add PPS time stamp if available via ppsclock module 2245 1.1 kardel * and not supplied already. 2246 1.1 kardel */ 2247 1.1 kardel if (parse->flags & PARSE_CLEAR) 2248 1.1 kardel pts = pps_info.clear_timestamp; 2249 1.1 kardel else 2250 1.1 kardel pts = pps_info.assert_timestamp; 2251 1.1 kardel 2252 1.15 christos parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970); 2253 1.1 kardel 2254 1.15 christos dtemp = (double) pts.tv_nsec / 1e9; 2255 1.1 kardel if (dtemp < 0.) { 2256 1.1 kardel dtemp += 1; 2257 1.1 kardel parse->parseio.parse_dtime.parse_ptime.fp.l_ui--; 2258 1.1 kardel } 2259 1.1 kardel if (dtemp > 1.) { 2260 1.1 kardel dtemp -= 1; 2261 1.1 kardel parse->parseio.parse_dtime.parse_ptime.fp.l_ui++; 2262 1.1 kardel } 2263 1.15 christos parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC); 2264 1.1 kardel 2265 1.15 christos parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2266 1.1 kardel #ifdef DEBUG 2267 1.1 kardel if (debug > 3) 2268 1.1 kardel { 2269 1.1 kardel printf( 2270 1.19 christos "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n", 2271 1.19 christos (long)rbufp->fd, 2272 1.1 kardel (long)pps_info.assert_sequence + (long)pps_info.clear_sequence, 2273 1.1 kardel lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6)); 2274 1.1 kardel } 2275 1.1 kardel #endif 2276 1.1 kardel } 2277 1.1 kardel #ifdef DEBUG 2278 1.1 kardel else 2279 1.1 kardel { 2280 1.1 kardel if (debug > 3) 2281 1.1 kardel { 2282 1.1 kardel printf( 2283 1.19 christos "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2284 1.19 christos (long)rbufp->fd, 2285 1.1 kardel (long)pps_info.assert_sequence, (long)pps_info.clear_sequence); 2286 1.1 kardel } 2287 1.1 kardel } 2288 1.1 kardel #endif 2289 1.1 kardel parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence; 2290 1.1 kardel } 2291 1.1 kardel #ifdef DEBUG 2292 1.1 kardel else 2293 1.1 kardel { 2294 1.1 kardel if (debug > 3) 2295 1.1 kardel { 2296 1.1 kardel printf( 2297 1.19 christos "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n", 2298 1.19 christos (long)rbufp->fd, 2299 1.1 kardel errno); 2300 1.1 kardel } 2301 1.1 kardel } 2302 1.1 kardel #endif 2303 1.1 kardel } 2304 1.1 kardel #else 2305 1.1 kardel #ifdef TIOCDCDTIMESTAMP 2306 1.1 kardel struct timeval dcd_time; 2307 1.15 christos 2308 1.1 kardel if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 2309 1.1 kardel { 2310 1.1 kardel l_fp tstmp; 2311 1.15 christos 2312 1.1 kardel TVTOTS(&dcd_time, &tstmp); 2313 1.1 kardel tstmp.l_ui += JAN_1970; 2314 1.1 kardel L_SUB(&ts.fp, &tstmp); 2315 1.1 kardel if (ts.fp.l_ui == 0) 2316 1.1 kardel { 2317 1.1 kardel #ifdef DEBUG 2318 1.1 kardel if (debug) 2319 1.1 kardel { 2320 1.1 kardel printf( 2321 1.1 kardel "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 2322 1.1 kardel parse->ppsfd, 2323 1.1 kardel lfptoa(&tstmp, 6)); 2324 1.1 kardel printf(" sigio %s\n", 2325 1.1 kardel lfptoa(&ts.fp, 6)); 2326 1.1 kardel } 2327 1.1 kardel #endif 2328 1.1 kardel parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 2329 1.1 kardel parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2330 1.1 kardel } 2331 1.1 kardel } 2332 1.1 kardel #else /* TIOCDCDTIMESTAMP */ 2333 1.1 kardel #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 2334 1.1 kardel if (parse->flags & PARSE_PPSCLOCK) 2335 1.1 kardel { 2336 1.1 kardel l_fp tts; 2337 1.1 kardel struct ppsclockev ev; 2338 1.1 kardel 2339 1.1 kardel #ifdef HAVE_CIOGETEV 2340 1.1 kardel if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0) 2341 1.1 kardel #endif 2342 1.1 kardel #ifdef HAVE_TIOCGPPSEV 2343 1.1 kardel if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0) 2344 1.1 kardel #endif 2345 1.1 kardel { 2346 1.1 kardel if (ev.serial != parse->ppsserial) 2347 1.1 kardel { 2348 1.1 kardel /* 2349 1.1 kardel * add PPS time stamp if available via ppsclock module 2350 1.1 kardel * and not supplied already. 2351 1.1 kardel */ 2352 1.1 kardel if (!buftvtots((const char *)&ev.tv, &tts)) 2353 1.1 kardel { 2354 1.1 kardel ERR(ERR_BADDATA) 2355 1.1 kardel msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 2356 1.1 kardel } 2357 1.1 kardel else 2358 1.1 kardel { 2359 1.1 kardel parse->parseio.parse_dtime.parse_ptime.fp = tts; 2360 1.1 kardel parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2361 1.1 kardel } 2362 1.1 kardel } 2363 1.1 kardel parse->ppsserial = ev.serial; 2364 1.1 kardel } 2365 1.1 kardel } 2366 1.1 kardel #endif 2367 1.1 kardel #endif /* TIOCDCDTIMESTAMP */ 2368 1.1 kardel #endif /* !HAVE_PPSAPI */ 2369 1.1 kardel } 2370 1.1 kardel if (count) 2371 1.1 kardel { /* simulate receive */ 2372 1.24 christos buf = get_free_recv_buffer(TRUE); 2373 1.1 kardel if (buf != NULL) { 2374 1.1 kardel memmove((caddr_t)buf->recv_buffer, 2375 1.1 kardel (caddr_t)&parse->parseio.parse_dtime, 2376 1.1 kardel sizeof(parsetime_t)); 2377 1.1 kardel buf->recv_length = sizeof(parsetime_t); 2378 1.1 kardel buf->recv_time = rbufp->recv_time; 2379 1.10 christos #ifndef HAVE_IO_COMPLETION_PORT 2380 1.1 kardel buf->srcadr = rbufp->srcadr; 2381 1.10 christos #endif 2382 1.1 kardel buf->dstadr = rbufp->dstadr; 2383 1.1 kardel buf->receiver = rbufp->receiver; 2384 1.1 kardel buf->fd = rbufp->fd; 2385 1.1 kardel buf->X_from_where = rbufp->X_from_where; 2386 1.10 christos parse->generic->io.recvcount++; 2387 1.10 christos packets_received++; 2388 1.1 kardel add_full_recv_buffer(buf); 2389 1.10 christos #ifdef HAVE_IO_COMPLETION_PORT 2390 1.10 christos SetEvent(WaitableIoEventHandle); 2391 1.10 christos #endif 2392 1.1 kardel } 2393 1.1 kardel parse_iodone(&parse->parseio); 2394 1.1 kardel } 2395 1.1 kardel else 2396 1.1 kardel { 2397 1.1 kardel memmove((caddr_t)rbufp->recv_buffer, 2398 1.1 kardel (caddr_t)&parse->parseio.parse_dtime, 2399 1.1 kardel sizeof(parsetime_t)); 2400 1.1 kardel parse_iodone(&parse->parseio); 2401 1.1 kardel rbufp->recv_length = sizeof(parsetime_t); 2402 1.1 kardel return 1; /* got something & in place return */ 2403 1.1 kardel } 2404 1.1 kardel } 2405 1.1 kardel } 2406 1.1 kardel return 0; /* nothing to pass up */ 2407 1.1 kardel } 2408 1.1 kardel 2409 1.1 kardel /*-------------------------------------------------- 2410 1.1 kardel * local receive 2411 1.1 kardel */ 2412 1.1 kardel static void 2413 1.1 kardel local_receive( 2414 1.1 kardel struct recvbuf *rbufp 2415 1.1 kardel ) 2416 1.1 kardel { 2417 1.10 christos struct parseunit * parse; 2418 1.1 kardel parsetime_t parsetime; 2419 1.1 kardel 2420 1.10 christos parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 2421 1.1 kardel if (!parse->peer) 2422 1.1 kardel return; 2423 1.1 kardel 2424 1.1 kardel if (rbufp->recv_length != sizeof(parsetime_t)) 2425 1.1 kardel { 2426 1.1 kardel ERR(ERR_BADIO) 2427 1.1 kardel msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 2428 1.1 kardel CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 2429 1.1 kardel parse_event(parse, CEVNT_BADREPLY); 2430 1.1 kardel return; 2431 1.1 kardel } 2432 1.1 kardel clear_err(parse, ERR_BADIO); 2433 1.15 christos 2434 1.1 kardel memmove((caddr_t)&parsetime, 2435 1.1 kardel (caddr_t)rbufp->recv_buffer, 2436 1.1 kardel sizeof(parsetime_t)); 2437 1.1 kardel 2438 1.1 kardel #ifdef DEBUG 2439 1.1 kardel if (debug > 3) 2440 1.1 kardel { 2441 1.1 kardel printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n", 2442 1.1 kardel CLK_UNIT(parse->peer), 2443 1.1 kardel (unsigned int)parsetime.parse_status, 2444 1.1 kardel (unsigned int)parsetime.parse_state, 2445 1.1 kardel (unsigned long)parsetime.parse_time.fp.l_ui, 2446 1.1 kardel (unsigned long)parsetime.parse_time.fp.l_uf, 2447 1.1 kardel (unsigned long)parsetime.parse_stime.fp.l_ui, 2448 1.1 kardel (unsigned long)parsetime.parse_stime.fp.l_uf, 2449 1.1 kardel (unsigned long)parsetime.parse_ptime.fp.l_ui, 2450 1.1 kardel (unsigned long)parsetime.parse_ptime.fp.l_uf); 2451 1.1 kardel } 2452 1.1 kardel #endif 2453 1.1 kardel 2454 1.1 kardel parse_process(parse, &parsetime); 2455 1.1 kardel } 2456 1.1 kardel 2457 1.1 kardel /*-------------------------------------------------- 2458 1.1 kardel * init_iobinding - find and initialize lower layers 2459 1.1 kardel */ 2460 1.1 kardel static bind_t * 2461 1.1 kardel init_iobinding( 2462 1.1 kardel struct parseunit *parse 2463 1.1 kardel ) 2464 1.1 kardel { 2465 1.1 kardel bind_t *b = io_bindings; 2466 1.1 kardel 2467 1.1 kardel while (b->bd_description != (char *)0) 2468 1.1 kardel { 2469 1.1 kardel if ((*b->bd_init)(parse)) 2470 1.1 kardel { 2471 1.1 kardel return b; 2472 1.1 kardel } 2473 1.1 kardel b++; 2474 1.1 kardel } 2475 1.1 kardel return (bind_t *)0; 2476 1.1 kardel } 2477 1.1 kardel 2478 1.1 kardel /**=========================================================================== 2479 1.1 kardel ** support routines 2480 1.1 kardel **/ 2481 1.1 kardel 2482 1.15 christos static NTP_PRINTF(4, 5) char * 2483 1.6 christos ap(char *buffer, size_t len, char *pos, const char *fmt, ...) 2484 1.6 christos { 2485 1.6 christos va_list va; 2486 1.6 christos int l; 2487 1.8 christos size_t rem = len - (pos - buffer); 2488 1.8 christos 2489 1.8 christos if (rem == 0) 2490 1.8 christos return pos; 2491 1.6 christos 2492 1.6 christos va_start(va, fmt); 2493 1.8 christos l = vsnprintf(pos, rem, fmt, va); 2494 1.6 christos va_end(va); 2495 1.8 christos 2496 1.8 christos if (l != -1) { 2497 1.8 christos rem--; 2498 1.9 christos if (rem >= (size_t)l) 2499 1.8 christos pos += l; 2500 1.8 christos else 2501 1.8 christos pos += rem; 2502 1.8 christos } 2503 1.8 christos 2504 1.6 christos return pos; 2505 1.6 christos } 2506 1.6 christos 2507 1.1 kardel /*-------------------------------------------------- 2508 1.1 kardel * convert a flag field to a string 2509 1.1 kardel */ 2510 1.1 kardel static char * 2511 1.1 kardel parsestate( 2512 1.1 kardel u_long lstate, 2513 1.1 kardel char *buffer, 2514 1.1 kardel int size 2515 1.1 kardel ) 2516 1.1 kardel { 2517 1.1 kardel static struct bits 2518 1.1 kardel { 2519 1.1 kardel u_long bit; 2520 1.1 kardel const char *name; 2521 1.1 kardel } flagstrings[] = 2522 1.1 kardel { 2523 1.1 kardel { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 2524 1.1 kardel { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 2525 1.1 kardel { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 2526 1.1 kardel { PARSEB_DST, "DST" }, 2527 1.1 kardel { PARSEB_UTC, "UTC DISPLAY" }, 2528 1.1 kardel { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 2529 1.1 kardel { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 2530 1.1 kardel { PARSEB_LEAPSECOND, "LEAP SECOND" }, 2531 1.15 christos { PARSEB_CALLBIT, "CALL BIT" }, 2532 1.1 kardel { PARSEB_TIMECODE, "TIME CODE" }, 2533 1.1 kardel { PARSEB_PPS, "PPS" }, 2534 1.1 kardel { PARSEB_POSITION, "POSITION" }, 2535 1.3 christos { 0, NULL } 2536 1.1 kardel }; 2537 1.1 kardel 2538 1.1 kardel static struct sbits 2539 1.1 kardel { 2540 1.1 kardel u_long bit; 2541 1.1 kardel const char *name; 2542 1.1 kardel } sflagstrings[] = 2543 1.1 kardel { 2544 1.1 kardel { PARSEB_S_LEAP, "LEAP INDICATION" }, 2545 1.1 kardel { PARSEB_S_PPS, "PPS SIGNAL" }, 2546 1.16 christos { PARSEB_S_CALLBIT, "CALLBIT" }, 2547 1.1 kardel { PARSEB_S_POSITION, "POSITION" }, 2548 1.3 christos { 0, NULL } 2549 1.1 kardel }; 2550 1.1 kardel int i; 2551 1.1 kardel char *s, *t; 2552 1.1 kardel 2553 1.14 christos *buffer = '\0'; 2554 1.1 kardel s = t = buffer; 2555 1.1 kardel 2556 1.1 kardel i = 0; 2557 1.1 kardel while (flagstrings[i].bit) 2558 1.1 kardel { 2559 1.1 kardel if (flagstrings[i].bit & lstate) 2560 1.1 kardel { 2561 1.1 kardel if (s != t) 2562 1.6 christos t = ap(buffer, size, t, "; "); 2563 1.6 christos t = ap(buffer, size, t, "%s", flagstrings[i].name); 2564 1.1 kardel } 2565 1.1 kardel i++; 2566 1.1 kardel } 2567 1.1 kardel 2568 1.16 christos if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION)) 2569 1.1 kardel { 2570 1.1 kardel if (s != t) 2571 1.6 christos t = ap(buffer, size, t, "; "); 2572 1.1 kardel 2573 1.6 christos t = ap(buffer, size, t, "("); 2574 1.1 kardel 2575 1.6 christos s = t; 2576 1.1 kardel 2577 1.1 kardel i = 0; 2578 1.1 kardel while (sflagstrings[i].bit) 2579 1.1 kardel { 2580 1.1 kardel if (sflagstrings[i].bit & lstate) 2581 1.1 kardel { 2582 1.1 kardel if (t != s) 2583 1.1 kardel { 2584 1.6 christos t = ap(buffer, size, t, "; "); 2585 1.1 kardel } 2586 1.15 christos 2587 1.6 christos t = ap(buffer, size, t, "%s", 2588 1.6 christos sflagstrings[i].name); 2589 1.1 kardel } 2590 1.1 kardel i++; 2591 1.1 kardel } 2592 1.6 christos t = ap(buffer, size, t, ")"); 2593 1.17 christos /* t is unused here, but if we don't track it and 2594 1.17 christos * need it later, that's a bug waiting to happen. 2595 1.17 christos */ 2596 1.1 kardel } 2597 1.1 kardel return buffer; 2598 1.1 kardel } 2599 1.1 kardel 2600 1.1 kardel /*-------------------------------------------------- 2601 1.1 kardel * convert a status flag field to a string 2602 1.1 kardel */ 2603 1.1 kardel static char * 2604 1.1 kardel parsestatus( 2605 1.1 kardel u_long lstate, 2606 1.1 kardel char *buffer, 2607 1.1 kardel int size 2608 1.1 kardel ) 2609 1.1 kardel { 2610 1.1 kardel static struct bits 2611 1.1 kardel { 2612 1.1 kardel u_long bit; 2613 1.1 kardel const char *name; 2614 1.1 kardel } flagstrings[] = 2615 1.1 kardel { 2616 1.1 kardel { CVT_OK, "CONVERSION SUCCESSFUL" }, 2617 1.1 kardel { CVT_NONE, "NO CONVERSION" }, 2618 1.1 kardel { CVT_FAIL, "CONVERSION FAILED" }, 2619 1.1 kardel { CVT_BADFMT, "ILLEGAL FORMAT" }, 2620 1.1 kardel { CVT_BADDATE, "DATE ILLEGAL" }, 2621 1.1 kardel { CVT_BADTIME, "TIME ILLEGAL" }, 2622 1.1 kardel { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 2623 1.3 christos { 0, NULL } 2624 1.1 kardel }; 2625 1.1 kardel int i; 2626 1.6 christos char *t; 2627 1.1 kardel 2628 1.6 christos t = buffer; 2629 1.1 kardel *buffer = '\0'; 2630 1.1 kardel 2631 1.1 kardel i = 0; 2632 1.1 kardel while (flagstrings[i].bit) 2633 1.1 kardel { 2634 1.1 kardel if (flagstrings[i].bit & lstate) 2635 1.1 kardel { 2636 1.15 christos if (t != buffer) 2637 1.6 christos t = ap(buffer, size, t, "; "); 2638 1.6 christos t = ap(buffer, size, t, "%s", flagstrings[i].name); 2639 1.1 kardel } 2640 1.1 kardel i++; 2641 1.1 kardel } 2642 1.1 kardel 2643 1.1 kardel return buffer; 2644 1.1 kardel } 2645 1.1 kardel 2646 1.1 kardel /*-------------------------------------------------- 2647 1.1 kardel * convert a clock status flag field to a string 2648 1.1 kardel */ 2649 1.1 kardel static const char * 2650 1.1 kardel clockstatus( 2651 1.1 kardel u_long lstate 2652 1.1 kardel ) 2653 1.1 kardel { 2654 1.1 kardel static char buffer[20]; 2655 1.1 kardel static struct status 2656 1.1 kardel { 2657 1.1 kardel u_long value; 2658 1.1 kardel const char *name; 2659 1.1 kardel } flagstrings[] = 2660 1.1 kardel { 2661 1.1 kardel { CEVNT_NOMINAL, "NOMINAL" }, 2662 1.1 kardel { CEVNT_TIMEOUT, "NO RESPONSE" }, 2663 1.1 kardel { CEVNT_BADREPLY,"BAD FORMAT" }, 2664 1.1 kardel { CEVNT_FAULT, "FAULT" }, 2665 1.1 kardel { CEVNT_PROP, "PROPAGATION DELAY" }, 2666 1.1 kardel { CEVNT_BADDATE, "ILLEGAL DATE" }, 2667 1.1 kardel { CEVNT_BADTIME, "ILLEGAL TIME" }, 2668 1.3 christos { (unsigned)~0L, NULL } 2669 1.1 kardel }; 2670 1.1 kardel int i; 2671 1.1 kardel 2672 1.1 kardel i = 0; 2673 1.3 christos while (flagstrings[i].value != (u_int)~0) 2674 1.1 kardel { 2675 1.1 kardel if (flagstrings[i].value == lstate) 2676 1.1 kardel { 2677 1.1 kardel return flagstrings[i].name; 2678 1.1 kardel } 2679 1.1 kardel i++; 2680 1.1 kardel } 2681 1.1 kardel 2682 1.1 kardel snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate); 2683 1.1 kardel 2684 1.1 kardel return buffer; 2685 1.1 kardel } 2686 1.1 kardel 2687 1.1 kardel 2688 1.1 kardel /*-------------------------------------------------- 2689 1.1 kardel * l_mktime - make representation of a relative time 2690 1.1 kardel */ 2691 1.1 kardel static char * 2692 1.1 kardel l_mktime( 2693 1.1 kardel u_long delta 2694 1.1 kardel ) 2695 1.1 kardel { 2696 1.1 kardel u_long tmp, m, s; 2697 1.1 kardel static char buffer[40]; 2698 1.1 kardel char *t; 2699 1.1 kardel 2700 1.1 kardel buffer[0] = '\0'; 2701 1.6 christos t = buffer; 2702 1.1 kardel 2703 1.1 kardel if ((tmp = delta / (60*60*24)) != 0) 2704 1.1 kardel { 2705 1.6 christos t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp); 2706 1.1 kardel delta -= tmp * 60*60*24; 2707 1.1 kardel } 2708 1.1 kardel 2709 1.1 kardel s = delta % 60; 2710 1.1 kardel delta /= 60; 2711 1.1 kardel m = delta % 60; 2712 1.1 kardel delta /= 60; 2713 1.1 kardel 2714 1.6 christos t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d", 2715 1.6 christos (int)delta, (int)m, (int)s); 2716 1.1 kardel 2717 1.1 kardel return buffer; 2718 1.1 kardel } 2719 1.1 kardel 2720 1.1 kardel 2721 1.1 kardel /*-------------------------------------------------- 2722 1.1 kardel * parse_statistics - list summary of clock states 2723 1.1 kardel */ 2724 1.1 kardel static void 2725 1.1 kardel parse_statistics( 2726 1.1 kardel struct parseunit *parse 2727 1.1 kardel ) 2728 1.1 kardel { 2729 1.1 kardel int i; 2730 1.1 kardel 2731 1.1 kardel NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 2732 1.1 kardel { 2733 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 2734 1.1 kardel CLK_UNIT(parse->peer), 2735 1.1 kardel l_mktime(current_time - parse->generic->timestarted)); 2736 1.1 kardel 2737 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 2738 1.1 kardel CLK_UNIT(parse->peer), 2739 1.1 kardel clockstatus(parse->generic->currentstatus)); 2740 1.1 kardel 2741 1.1 kardel for (i = 0; i <= CEVNT_MAX; i++) 2742 1.1 kardel { 2743 1.1 kardel u_long s_time; 2744 1.1 kardel u_long percent, d = current_time - parse->generic->timestarted; 2745 1.1 kardel 2746 1.1 kardel percent = s_time = PARSE_STATETIME(parse, i); 2747 1.1 kardel 2748 1.1 kardel while (((u_long)(~0) / 10000) < percent) 2749 1.1 kardel { 2750 1.1 kardel percent /= 10; 2751 1.1 kardel d /= 10; 2752 1.1 kardel } 2753 1.1 kardel 2754 1.1 kardel if (d) 2755 1.1 kardel percent = (percent * 10000) / d; 2756 1.1 kardel else 2757 1.1 kardel percent = 10000; 2758 1.1 kardel 2759 1.1 kardel if (s_time) 2760 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 2761 1.1 kardel CLK_UNIT(parse->peer), 2762 1.1 kardel clockstatus((unsigned int)i), 2763 1.1 kardel l_mktime(s_time), 2764 1.1 kardel percent / 100, percent % 100); 2765 1.1 kardel } 2766 1.1 kardel } 2767 1.1 kardel } 2768 1.1 kardel 2769 1.1 kardel /*-------------------------------------------------- 2770 1.1 kardel * cparse_statistics - wrapper for statistics call 2771 1.1 kardel */ 2772 1.1 kardel static void 2773 1.1 kardel cparse_statistics( 2774 1.1 kardel struct parseunit *parse 2775 1.1 kardel ) 2776 1.1 kardel { 2777 1.1 kardel if (parse->laststatistic + PARSESTATISTICS < current_time) 2778 1.1 kardel parse_statistics(parse); 2779 1.1 kardel parse->laststatistic = current_time; 2780 1.1 kardel } 2781 1.1 kardel 2782 1.1 kardel /**=========================================================================== 2783 1.1 kardel ** ntp interface routines 2784 1.1 kardel **/ 2785 1.1 kardel 2786 1.1 kardel /*-------------------------------------------------- 2787 1.1 kardel * parse_shutdown - shut down a PARSE clock 2788 1.1 kardel */ 2789 1.1 kardel static void 2790 1.1 kardel parse_shutdown( 2791 1.1 kardel int unit, 2792 1.1 kardel struct peer *peer 2793 1.1 kardel ) 2794 1.1 kardel { 2795 1.10 christos struct parseunit *parse = NULL; 2796 1.1 kardel 2797 1.1 kardel if (peer && peer->procptr) 2798 1.10 christos parse = peer->procptr->unitptr; 2799 1.1 kardel 2800 1.1 kardel if (!parse) 2801 1.1 kardel { 2802 1.1 kardel /* nothing to clean up */ 2803 1.1 kardel return; 2804 1.1 kardel } 2805 1.1 kardel 2806 1.10 christos if (!parse->peer) 2807 1.1 kardel { 2808 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit); 2809 1.1 kardel return; 2810 1.1 kardel } 2811 1.1 kardel 2812 1.1 kardel #ifdef HAVE_PPSAPI 2813 1.1 kardel if (parse->flags & PARSE_PPSCLOCK) 2814 1.1 kardel { 2815 1.1 kardel (void)time_pps_destroy(parse->atom.handle); 2816 1.1 kardel } 2817 1.1 kardel #endif 2818 1.1 kardel if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2819 1.10 christos (void)closeserial(parse->ppsfd); /* close separate PPS source */ 2820 1.1 kardel 2821 1.1 kardel /* 2822 1.1 kardel * print statistics a last time and 2823 1.1 kardel * stop statistics machine 2824 1.1 kardel */ 2825 1.1 kardel parse_statistics(parse); 2826 1.1 kardel 2827 1.1 kardel if (parse->parse_type->cl_end) 2828 1.1 kardel { 2829 1.1 kardel parse->parse_type->cl_end(parse); 2830 1.1 kardel } 2831 1.15 christos 2832 1.1 kardel /* 2833 1.1 kardel * cleanup before leaving this world 2834 1.1 kardel */ 2835 1.1 kardel if (parse->binding) 2836 1.1 kardel PARSE_END(parse); 2837 1.1 kardel 2838 1.1 kardel /* 2839 1.1 kardel * Tell the I/O module to turn us off. We're history. 2840 1.1 kardel */ 2841 1.1 kardel io_closeclock(&parse->generic->io); 2842 1.1 kardel 2843 1.1 kardel free_varlist(parse->kv); 2844 1.15 christos 2845 1.1 kardel NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2846 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 2847 1.1 kardel CLK_UNIT(parse->peer), parse->parse_type->cl_description); 2848 1.1 kardel 2849 1.1 kardel parse->peer = (struct peer *)0; /* unused now */ 2850 1.1 kardel peer->procptr->unitptr = (caddr_t)0; 2851 1.1 kardel free(parse); 2852 1.1 kardel } 2853 1.1 kardel 2854 1.1 kardel #ifdef HAVE_PPSAPI 2855 1.1 kardel /*---------------------------------------- 2856 1.1 kardel * set up HARDPPS via PPSAPI 2857 1.1 kardel */ 2858 1.1 kardel static void 2859 1.1 kardel parse_hardpps( 2860 1.1 kardel struct parseunit *parse, 2861 1.1 kardel int mode 2862 1.1 kardel ) 2863 1.1 kardel { 2864 1.1 kardel if (parse->hardppsstate == mode) 2865 1.1 kardel return; 2866 1.1 kardel 2867 1.1 kardel if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) { 2868 1.1 kardel int i = 0; 2869 1.1 kardel 2870 1.15 christos if (mode == PARSE_HARDPPS_ENABLE) 2871 1.1 kardel { 2872 1.1 kardel if (parse->flags & PARSE_CLEAR) 2873 1.1 kardel i = PPS_CAPTURECLEAR; 2874 1.1 kardel else 2875 1.1 kardel i = PPS_CAPTUREASSERT; 2876 1.1 kardel } 2877 1.15 christos 2878 1.1 kardel if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i, 2879 1.1 kardel PPS_TSFMT_TSPEC) < 0) { 2880 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m", 2881 1.1 kardel CLK_UNIT(parse->peer)); 2882 1.1 kardel } else { 2883 1.1 kardel NLOG(NLOG_CLOCKINFO) 2884 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled", 2885 1.1 kardel CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis"); 2886 1.1 kardel /* 2887 1.1 kardel * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS 2888 1.1 kardel */ 2889 1.1 kardel if (mode == PARSE_HARDPPS_ENABLE) 2890 1.13 christos hardpps_enable = 1; 2891 1.1 kardel } 2892 1.1 kardel } 2893 1.1 kardel 2894 1.1 kardel parse->hardppsstate = mode; 2895 1.1 kardel } 2896 1.1 kardel 2897 1.1 kardel /*---------------------------------------- 2898 1.1 kardel * set up PPS via PPSAPI 2899 1.1 kardel */ 2900 1.1 kardel static int 2901 1.1 kardel parse_ppsapi( 2902 1.1 kardel struct parseunit *parse 2903 1.1 kardel ) 2904 1.1 kardel { 2905 1.1 kardel int cap, mode_ppsoffset; 2906 1.3 christos const char *cp; 2907 1.15 christos 2908 1.15 christos parse->flags &= (u_char) (~PARSE_PPSCLOCK); 2909 1.1 kardel 2910 1.1 kardel /* 2911 1.1 kardel * collect PPSAPI offset capability - should move into generic handling 2912 1.1 kardel */ 2913 1.1 kardel if (time_pps_getcap(parse->atom.handle, &cap) < 0) { 2914 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m", 2915 1.1 kardel CLK_UNIT(parse->peer)); 2916 1.15 christos 2917 1.1 kardel return 0; 2918 1.1 kardel } 2919 1.1 kardel 2920 1.1 kardel /* 2921 1.1 kardel * initialize generic PPSAPI interface 2922 1.1 kardel * 2923 1.1 kardel * we leave out CLK_FLAG3 as time_pps_kcbind() 2924 1.1 kardel * is handled here for now. Ideally this should also 2925 1.1 kardel * be part of the generic PPSAPI interface 2926 1.1 kardel */ 2927 1.1 kardel if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom)) 2928 1.1 kardel return 0; 2929 1.1 kardel 2930 1.1 kardel /* nb. only turn things on, if someone else has turned something 2931 1.1 kardel * on before we get here, leave it alone! 2932 1.1 kardel */ 2933 1.1 kardel 2934 1.1 kardel if (parse->flags & PARSE_CLEAR) { 2935 1.1 kardel cp = "CLEAR"; 2936 1.1 kardel mode_ppsoffset = PPS_OFFSETCLEAR; 2937 1.1 kardel } else { 2938 1.1 kardel cp = "ASSERT"; 2939 1.1 kardel mode_ppsoffset = PPS_OFFSETASSERT; 2940 1.1 kardel } 2941 1.1 kardel 2942 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2943 1.1 kardel CLK_UNIT(parse->peer), cp); 2944 1.1 kardel 2945 1.1 kardel if (!(mode_ppsoffset & cap)) { 2946 1.1 kardel msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)", 2947 1.1 kardel CLK_UNIT(parse->peer), cp, cap); 2948 1.1 kardel mode_ppsoffset = 0; 2949 1.1 kardel } else { 2950 1.15 christos if (mode_ppsoffset == PPS_OFFSETCLEAR) 2951 1.15 christos { 2952 1.15 christos parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2953 1.15 christos parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2954 1.1 kardel } 2955 1.15 christos 2956 1.1 kardel if (mode_ppsoffset == PPS_OFFSETASSERT) 2957 1.15 christos { 2958 1.15 christos parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2959 1.15 christos parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2960 1.1 kardel } 2961 1.1 kardel } 2962 1.15 christos 2963 1.1 kardel parse->atom.pps_params.mode |= mode_ppsoffset; 2964 1.1 kardel 2965 1.1 kardel if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) { 2966 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m", 2967 1.1 kardel CLK_UNIT(parse->peer)); 2968 1.1 kardel return 0; 2969 1.1 kardel } 2970 1.1 kardel 2971 1.1 kardel parse->flags |= PARSE_PPSCLOCK; 2972 1.1 kardel return 1; 2973 1.1 kardel } 2974 1.1 kardel #else 2975 1.1 kardel #define parse_hardpps(_PARSE_, _MODE_) /* empty */ 2976 1.1 kardel #endif 2977 1.1 kardel 2978 1.1 kardel /*-------------------------------------------------- 2979 1.1 kardel * parse_start - open the PARSE devices and initialize data for processing 2980 1.1 kardel */ 2981 1.1 kardel static int 2982 1.1 kardel parse_start( 2983 1.1 kardel int sysunit, 2984 1.1 kardel struct peer *peer 2985 1.1 kardel ) 2986 1.1 kardel { 2987 1.1 kardel u_int unit; 2988 1.1 kardel int fd232; 2989 1.1 kardel #ifdef HAVE_TERMIOS 2990 1.1 kardel struct termios tio; /* NEEDED FOR A LONG TIME ! */ 2991 1.1 kardel #endif 2992 1.1 kardel #ifdef HAVE_SYSV_TTYS 2993 1.1 kardel struct termio tio; /* NEEDED FOR A LONG TIME ! */ 2994 1.1 kardel #endif 2995 1.1 kardel struct parseunit * parse; 2996 1.1 kardel char parsedev[sizeof(PARSEDEVICE)+20]; 2997 1.1 kardel char parseppsdev[sizeof(PARSEPPSDEVICE)+20]; 2998 1.25 christos const char *altdev; 2999 1.1 kardel parsectl_t tmp_ctl; 3000 1.1 kardel u_int type; 3001 1.1 kardel 3002 1.1 kardel /* 3003 1.1 kardel * get out Copyright information once 3004 1.1 kardel */ 3005 1.1 kardel if (!notice) 3006 1.1 kardel { 3007 1.1 kardel NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3008 1.16 christos msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2015, Frank Kardel"); 3009 1.1 kardel notice = 1; 3010 1.1 kardel } 3011 1.1 kardel 3012 1.1 kardel type = CLK_TYPE(peer); 3013 1.1 kardel unit = CLK_UNIT(peer); 3014 1.1 kardel 3015 1.3 christos if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0)) 3016 1.1 kardel { 3017 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 3018 1.1 kardel unit, CLK_REALTYPE(peer), ncltypes-1); 3019 1.1 kardel return 0; 3020 1.1 kardel } 3021 1.1 kardel 3022 1.1 kardel /* 3023 1.1 kardel * Unit okay, attempt to open the device. 3024 1.1 kardel */ 3025 1.25 christos 3026 1.25 christos /* see if there's a configured alternative device name: */ 3027 1.25 christos altdev = clockdev_lookup(&peer->srcadr, 0); 3028 1.25 christos if (altdev && (strlen(altdev) < sizeof(parsedev))) 3029 1.25 christos strcpy(parsedev, altdev); 3030 1.25 christos else 3031 1.25 christos (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit); 3032 1.25 christos 3033 1.25 christos /* likewise for a pps device: */ 3034 1.25 christos altdev = clockdev_lookup(&peer->srcadr, 1); 3035 1.25 christos if (altdev && (strlen(altdev) < sizeof(parseppsdev))) 3036 1.25 christos strcpy(parseppsdev, altdev); 3037 1.25 christos else 3038 1.25 christos (void) snprintf(parseppsdev, sizeof(parseppsdev), PARSEPPSDEVICE, unit); 3039 1.1 kardel 3040 1.1 kardel #ifndef O_NOCTTY 3041 1.1 kardel #define O_NOCTTY 0 3042 1.1 kardel #endif 3043 1.10 christos #ifndef O_NONBLOCK 3044 1.10 christos #define O_NONBLOCK 0 3045 1.10 christos #endif 3046 1.1 kardel 3047 1.10 christos fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3048 1.1 kardel 3049 1.1 kardel if (fd232 == -1) 3050 1.1 kardel { 3051 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 3052 1.1 kardel return 0; 3053 1.1 kardel } 3054 1.1 kardel 3055 1.10 christos parse = emalloc_zero(sizeof(*parse)); 3056 1.1 kardel 3057 1.1 kardel parse->generic = peer->procptr; /* link up */ 3058 1.1 kardel parse->generic->unitptr = (caddr_t)parse; /* link down */ 3059 1.1 kardel 3060 1.1 kardel /* 3061 1.1 kardel * Set up the structures 3062 1.1 kardel */ 3063 1.1 kardel parse->generic->timestarted = current_time; 3064 1.1 kardel parse->lastchange = current_time; 3065 1.1 kardel 3066 1.1 kardel parse->flags = 0; 3067 1.1 kardel parse->pollneeddata = 0; 3068 1.1 kardel parse->laststatistic = current_time; 3069 1.1 kardel parse->lastformat = (unsigned short)~0; /* assume no format known */ 3070 1.1 kardel parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 3071 1.1 kardel parse->lastmissed = 0; /* assume got everything */ 3072 1.1 kardel parse->ppsserial = 0; 3073 1.1 kardel parse->ppsfd = -1; 3074 1.1 kardel parse->localdata = (void *)0; 3075 1.1 kardel parse->localstate = 0; 3076 1.1 kardel parse->kv = (struct ctl_var *)0; 3077 1.1 kardel 3078 1.1 kardel clear_err(parse, ERR_ALL); 3079 1.15 christos 3080 1.1 kardel parse->parse_type = &parse_clockinfo[type]; 3081 1.15 christos 3082 1.1 kardel parse->maxunsync = parse->parse_type->cl_maxunsync; 3083 1.1 kardel 3084 1.1 kardel parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 3085 1.1 kardel 3086 1.1 kardel parse->generic->fudgetime2 = 0.0; 3087 1.1 kardel parse->ppsphaseadjust = parse->generic->fudgetime2; 3088 1.22 christos parse->generic->fudgeminjitter = 0.0; 3089 1.1 kardel 3090 1.1 kardel parse->generic->clockdesc = parse->parse_type->cl_description; 3091 1.1 kardel 3092 1.1 kardel peer->rootdelay = parse->parse_type->cl_rootdelay; 3093 1.1 kardel peer->sstclktype = parse->parse_type->cl_type; 3094 1.1 kardel peer->precision = sys_precision; 3095 1.15 christos 3096 1.1 kardel peer->stratum = STRATUM_REFCLOCK; 3097 1.1 kardel 3098 1.1 kardel if (peer->stratum <= 1) 3099 1.1 kardel memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 3100 1.1 kardel else 3101 1.1 kardel parse->generic->refid = htonl(PARSEHSREFID); 3102 1.15 christos 3103 1.1 kardel parse->generic->io.fd = fd232; 3104 1.15 christos 3105 1.1 kardel parse->peer = peer; /* marks it also as busy */ 3106 1.1 kardel 3107 1.1 kardel /* 3108 1.1 kardel * configure terminal line 3109 1.1 kardel */ 3110 1.1 kardel if (TTY_GETATTR(fd232, &tio) == -1) 3111 1.1 kardel { 3112 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 3113 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3114 1.1 kardel return 0; 3115 1.1 kardel } 3116 1.1 kardel else 3117 1.1 kardel { 3118 1.1 kardel #ifndef _PC_VDISABLE 3119 1.1 kardel memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 3120 1.1 kardel #else 3121 1.1 kardel int disablec; 3122 1.1 kardel errno = 0; /* pathconf can deliver -1 without changing errno ! */ 3123 1.1 kardel 3124 1.1 kardel disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 3125 1.1 kardel if (disablec == -1 && errno) 3126 1.1 kardel { 3127 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 3128 1.1 kardel memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 3129 1.1 kardel } 3130 1.1 kardel else 3131 1.1 kardel if (disablec != -1) 3132 1.1 kardel memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 3133 1.1 kardel #endif 3134 1.1 kardel 3135 1.1 kardel #if defined (VMIN) || defined(VTIME) 3136 1.1 kardel if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 3137 1.1 kardel { 3138 1.1 kardel #ifdef VMIN 3139 1.1 kardel tio.c_cc[VMIN] = 1; 3140 1.1 kardel #endif 3141 1.1 kardel #ifdef VTIME 3142 1.1 kardel tio.c_cc[VTIME] = 0; 3143 1.1 kardel #endif 3144 1.1 kardel } 3145 1.1 kardel #endif 3146 1.1 kardel 3147 1.15 christos tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag; 3148 1.15 christos tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag; 3149 1.15 christos tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag; 3150 1.15 christos tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag; 3151 1.15 christos 3152 1.1 kardel 3153 1.1 kardel #ifdef HAVE_TERMIOS 3154 1.15 christos if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) || 3155 1.15 christos (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1)) 3156 1.1 kardel { 3157 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 3158 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3159 1.1 kardel return 0; 3160 1.1 kardel } 3161 1.1 kardel #else 3162 1.1 kardel tio.c_cflag |= parse_clockinfo[type].cl_speed; 3163 1.1 kardel #endif 3164 1.1 kardel 3165 1.1 kardel /* 3166 1.1 kardel * set up pps device 3167 1.1 kardel * if the PARSEPPSDEVICE can be opened that will be used 3168 1.1 kardel * for PPS else PARSEDEVICE will be used 3169 1.1 kardel */ 3170 1.10 christos parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3171 1.1 kardel 3172 1.1 kardel if (parse->ppsfd == -1) 3173 1.1 kardel { 3174 1.1 kardel parse->ppsfd = fd232; 3175 1.1 kardel } 3176 1.1 kardel 3177 1.1 kardel /* 3178 1.1 kardel * Linux PPS - the old way 3179 1.1 kardel */ 3180 1.1 kardel #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 3181 1.1 kardel { 3182 1.1 kardel struct serial_struct ss; 3183 1.1 kardel if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 3184 1.1 kardel ( 3185 1.1 kardel #ifdef ASYNC_LOW_LATENCY 3186 1.1 kardel ss.flags |= ASYNC_LOW_LATENCY, 3187 1.1 kardel #endif 3188 1.1 kardel #ifndef HAVE_PPSAPI 3189 1.1 kardel #ifdef ASYNC_PPS_CD_NEG 3190 1.1 kardel ss.flags |= ASYNC_PPS_CD_NEG, 3191 1.1 kardel #endif 3192 1.1 kardel #endif 3193 1.1 kardel ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3194 1.1 kardel msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3195 1.1 kardel msyslog(LOG_NOTICE, 3196 1.1 kardel "refclock_parse: optional PPS processing not available"); 3197 1.1 kardel } else { 3198 1.1 kardel parse->flags |= PARSE_PPSCLOCK; 3199 1.1 kardel #ifdef ASYNC_PPS_CD_NEG 3200 1.1 kardel NLOG(NLOG_CLOCKINFO) 3201 1.1 kardel msyslog(LOG_INFO, 3202 1.1 kardel "refclock_parse: PPS detection on"); 3203 1.1 kardel #endif 3204 1.1 kardel } 3205 1.1 kardel } 3206 1.1 kardel #endif 3207 1.1 kardel 3208 1.1 kardel /* 3209 1.1 kardel * SUN the Solaris way 3210 1.1 kardel */ 3211 1.1 kardel #ifdef HAVE_TIOCSPPS /* SUN PPS support */ 3212 1.1 kardel if (CLK_PPS(parse->peer)) 3213 1.1 kardel { 3214 1.1 kardel int i = 1; 3215 1.15 christos 3216 1.1 kardel if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3217 1.1 kardel { 3218 1.1 kardel parse->flags |= PARSE_PPSCLOCK; 3219 1.1 kardel } 3220 1.1 kardel } 3221 1.1 kardel #endif 3222 1.1 kardel 3223 1.1 kardel /* 3224 1.1 kardel * PPS via PPSAPI 3225 1.1 kardel */ 3226 1.1 kardel #if defined(HAVE_PPSAPI) 3227 1.1 kardel parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3228 1.1 kardel if (CLK_PPS(parse->peer)) 3229 1.1 kardel { 3230 1.1 kardel if (!refclock_ppsapi(parse->ppsfd, &parse->atom)) 3231 1.1 kardel { 3232 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3233 1.1 kardel } 3234 1.1 kardel else 3235 1.1 kardel { 3236 1.1 kardel parse_ppsapi(parse); 3237 1.1 kardel } 3238 1.1 kardel } 3239 1.1 kardel #endif 3240 1.1 kardel 3241 1.1 kardel if (TTY_SETATTR(fd232, &tio) == -1) 3242 1.1 kardel { 3243 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 3244 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3245 1.1 kardel return 0; 3246 1.1 kardel } 3247 1.1 kardel } 3248 1.1 kardel 3249 1.1 kardel /* 3250 1.1 kardel * pick correct input machine 3251 1.1 kardel */ 3252 1.10 christos parse->generic->io.srcclock = peer; 3253 1.1 kardel parse->generic->io.datalen = 0; 3254 1.15 christos 3255 1.1 kardel parse->binding = init_iobinding(parse); 3256 1.1 kardel 3257 1.1 kardel if (parse->binding == (bind_t *)0) 3258 1.1 kardel { 3259 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 3260 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3261 1.1 kardel return 0; /* well, ok - special initialisation broke */ 3262 1.10 christos } 3263 1.1 kardel 3264 1.1 kardel parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3265 1.1 kardel parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3266 1.1 kardel 3267 1.1 kardel /* 3268 1.1 kardel * as we always(?) get 8 bit chars we want to be 3269 1.1 kardel * sure, that the upper bits are zero for less 3270 1.1 kardel * than 8 bit I/O - so we pass that information on. 3271 1.1 kardel * note that there can be only one bit count format 3272 1.1 kardel * per file descriptor 3273 1.1 kardel */ 3274 1.1 kardel 3275 1.1 kardel switch (tio.c_cflag & CSIZE) 3276 1.1 kardel { 3277 1.1 kardel case CS5: 3278 1.1 kardel tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 3279 1.1 kardel break; 3280 1.1 kardel 3281 1.1 kardel case CS6: 3282 1.1 kardel tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 3283 1.1 kardel break; 3284 1.1 kardel 3285 1.1 kardel case CS7: 3286 1.1 kardel tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 3287 1.1 kardel break; 3288 1.1 kardel 3289 1.1 kardel case CS8: 3290 1.1 kardel tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 3291 1.1 kardel break; 3292 1.1 kardel } 3293 1.1 kardel 3294 1.1 kardel if (!PARSE_SETCS(parse, &tmp_ctl)) 3295 1.1 kardel { 3296 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 3297 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3298 1.1 kardel return 0; /* well, ok - special initialisation broke */ 3299 1.1 kardel } 3300 1.15 christos 3301 1.6 christos strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 3302 1.15 christos tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer); 3303 1.1 kardel 3304 1.1 kardel if (!PARSE_SETFMT(parse, &tmp_ctl)) 3305 1.1 kardel { 3306 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 3307 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3308 1.1 kardel return 0; /* well, ok - special initialisation broke */ 3309 1.1 kardel } 3310 1.15 christos 3311 1.1 kardel /* 3312 1.1 kardel * get rid of all IO accumulated so far 3313 1.1 kardel */ 3314 1.1 kardel #ifdef HAVE_TERMIOS 3315 1.1 kardel (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 3316 1.1 kardel #else 3317 1.1 kardel #if defined(TCFLSH) && defined(TCIOFLUSH) 3318 1.1 kardel { 3319 1.1 kardel int flshcmd = TCIOFLUSH; 3320 1.1 kardel 3321 1.1 kardel (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 3322 1.1 kardel } 3323 1.1 kardel #endif 3324 1.1 kardel #endif 3325 1.1 kardel 3326 1.1 kardel /* 3327 1.1 kardel * try to do any special initializations 3328 1.1 kardel */ 3329 1.1 kardel if (parse->parse_type->cl_init) 3330 1.1 kardel { 3331 1.1 kardel if (parse->parse_type->cl_init(parse)) 3332 1.1 kardel { 3333 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3334 1.1 kardel return 0; /* well, ok - special initialisation broke */ 3335 1.1 kardel } 3336 1.1 kardel } 3337 1.15 christos 3338 1.1 kardel /* 3339 1.1 kardel * Insert in async io device list. 3340 1.1 kardel */ 3341 1.1 kardel if (!io_addclock(&parse->generic->io)) 3342 1.1 kardel { 3343 1.1 kardel msyslog(LOG_ERR, 3344 1.1 kardel "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3345 1.1 kardel parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3346 1.1 kardel return 0; 3347 1.1 kardel } 3348 1.1 kardel 3349 1.1 kardel /* 3350 1.1 kardel * print out configuration 3351 1.1 kardel */ 3352 1.1 kardel NLOG(NLOG_CLOCKINFO) 3353 1.1 kardel { 3354 1.1 kardel /* conditional if clause for conditional syslog */ 3355 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 3356 1.1 kardel CLK_UNIT(parse->peer), 3357 1.1 kardel parse->parse_type->cl_description, parsedev, 3358 1.1 kardel (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 3359 1.1 kardel 3360 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 3361 1.1 kardel CLK_UNIT(parse->peer), 3362 1.1 kardel parse->peer->stratum, 3363 1.1 kardel l_mktime(parse->maxunsync), parse->peer->precision); 3364 1.1 kardel 3365 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 3366 1.1 kardel CLK_UNIT(parse->peer), 3367 1.1 kardel parse->parse_type->cl_rootdelay, 3368 1.1 kardel parse->generic->fudgetime1, 3369 1.1 kardel parse->ppsphaseadjust, 3370 1.1 kardel parse->binding->bd_description); 3371 1.1 kardel 3372 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 3373 1.1 kardel parse->parse_type->cl_format); 3374 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3375 1.1 kardel CLK_PPS(parse->peer) ? "" : "NO ", 3376 1.1 kardel CLK_PPS(parse->peer) ? 3377 1.1 kardel #ifdef PPS_METHOD 3378 1.1 kardel " (implementation " PPS_METHOD ")" 3379 1.1 kardel #else 3380 1.1 kardel "" 3381 1.1 kardel #endif 3382 1.1 kardel : "" 3383 1.1 kardel ); 3384 1.1 kardel } 3385 1.1 kardel 3386 1.1 kardel return 1; 3387 1.1 kardel } 3388 1.1 kardel 3389 1.1 kardel /*-------------------------------------------------- 3390 1.1 kardel * parse_ctl - process changes on flags/time values 3391 1.1 kardel */ 3392 1.1 kardel static void 3393 1.1 kardel parse_ctl( 3394 1.1 kardel struct parseunit *parse, 3395 1.10 christos const struct refclockstat *in 3396 1.1 kardel ) 3397 1.1 kardel { 3398 1.1 kardel if (in) 3399 1.1 kardel { 3400 1.1 kardel if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3401 1.1 kardel { 3402 1.15 christos u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4; 3403 1.15 christos parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask); 3404 1.1 kardel #if defined(HAVE_PPSAPI) 3405 1.1 kardel if (CLK_PPS(parse->peer)) 3406 1.1 kardel { 3407 1.1 kardel parse_ppsapi(parse); 3408 1.1 kardel } 3409 1.1 kardel #endif 3410 1.1 kardel } 3411 1.15 christos 3412 1.1 kardel if (in->haveflags & CLK_HAVETIME1) 3413 1.1 kardel { 3414 1.1 kardel parse->generic->fudgetime1 = in->fudgetime1; 3415 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3416 1.1 kardel CLK_UNIT(parse->peer), 3417 1.1 kardel parse->generic->fudgetime1); 3418 1.1 kardel } 3419 1.15 christos 3420 1.1 kardel if (in->haveflags & CLK_HAVETIME2) 3421 1.1 kardel { 3422 1.1 kardel parse->generic->fudgetime2 = in->fudgetime2; 3423 1.15 christos if (parse->flags & PARSE_TRUSTTIME) 3424 1.1 kardel { 3425 1.1 kardel parse->maxunsync = (u_long)ABS(in->fudgetime2); 3426 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3427 1.1 kardel CLK_UNIT(parse->peer), 3428 1.1 kardel l_mktime(parse->maxunsync)); 3429 1.1 kardel } 3430 1.1 kardel else 3431 1.1 kardel { 3432 1.1 kardel parse->ppsphaseadjust = in->fudgetime2; 3433 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3434 1.1 kardel CLK_UNIT(parse->peer), 3435 1.1 kardel parse->ppsphaseadjust); 3436 1.1 kardel #if defined(HAVE_PPSAPI) 3437 1.1 kardel if (CLK_PPS(parse->peer)) 3438 1.1 kardel { 3439 1.1 kardel parse_ppsapi(parse); 3440 1.1 kardel } 3441 1.1 kardel #endif 3442 1.1 kardel } 3443 1.1 kardel } 3444 1.22 christos 3445 1.22 christos parse->generic->fudgeminjitter = in->fudgeminjitter; 3446 1.1 kardel } 3447 1.1 kardel } 3448 1.1 kardel 3449 1.1 kardel /*-------------------------------------------------- 3450 1.1 kardel * parse_poll - called by the transmit procedure 3451 1.1 kardel */ 3452 1.1 kardel static void 3453 1.1 kardel parse_poll( 3454 1.1 kardel int unit, 3455 1.1 kardel struct peer *peer 3456 1.1 kardel ) 3457 1.1 kardel { 3458 1.10 christos struct parseunit *parse = peer->procptr->unitptr; 3459 1.1 kardel 3460 1.1 kardel if (peer != parse->peer) 3461 1.1 kardel { 3462 1.1 kardel msyslog(LOG_ERR, 3463 1.1 kardel "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 3464 1.1 kardel unit); 3465 1.1 kardel return; 3466 1.1 kardel } 3467 1.1 kardel 3468 1.1 kardel /* 3469 1.1 kardel * Update clock stat counters 3470 1.1 kardel */ 3471 1.1 kardel parse->generic->polls++; 3472 1.1 kardel 3473 1.15 christos if (parse->pollneeddata && 3474 1.3 christos ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 3475 1.1 kardel { 3476 1.1 kardel /* 3477 1.1 kardel * start worrying when exceeding a poll inteval 3478 1.1 kardel * bad news - didn't get a response last time 3479 1.1 kardel */ 3480 1.1 kardel parse->lastmissed = current_time; 3481 1.1 kardel parse_event(parse, CEVNT_TIMEOUT); 3482 1.15 christos 3483 1.1 kardel ERR(ERR_NODATA) 3484 1.1 kardel msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 3485 1.1 kardel } 3486 1.1 kardel 3487 1.1 kardel /* 3488 1.1 kardel * we just mark that we want the next sample for the clock filter 3489 1.1 kardel */ 3490 1.1 kardel parse->pollneeddata = current_time; 3491 1.1 kardel 3492 1.1 kardel if (parse->parse_type->cl_poll) 3493 1.1 kardel { 3494 1.1 kardel parse->parse_type->cl_poll(parse); 3495 1.1 kardel } 3496 1.1 kardel 3497 1.1 kardel cparse_statistics(parse); 3498 1.1 kardel 3499 1.1 kardel return; 3500 1.1 kardel } 3501 1.1 kardel 3502 1.1 kardel #define LEN_STATES 300 /* length of state string */ 3503 1.1 kardel 3504 1.1 kardel /*-------------------------------------------------- 3505 1.1 kardel * parse_control - set fudge factors, return statistics 3506 1.1 kardel */ 3507 1.1 kardel static void 3508 1.1 kardel parse_control( 3509 1.1 kardel int unit, 3510 1.10 christos const struct refclockstat *in, 3511 1.1 kardel struct refclockstat *out, 3512 1.1 kardel struct peer *peer 3513 1.1 kardel ) 3514 1.1 kardel { 3515 1.10 christos struct parseunit *parse = peer->procptr->unitptr; 3516 1.1 kardel parsectl_t tmpctl; 3517 1.1 kardel 3518 1.1 kardel static char outstatus[400]; /* status output buffer */ 3519 1.1 kardel 3520 1.1 kardel if (out) 3521 1.1 kardel { 3522 1.1 kardel out->lencode = 0; 3523 1.1 kardel out->p_lastcode = 0; 3524 1.1 kardel out->kv_list = (struct ctl_var *)0; 3525 1.1 kardel } 3526 1.1 kardel 3527 1.1 kardel if (!parse || !parse->peer) 3528 1.1 kardel { 3529 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 3530 1.1 kardel unit); 3531 1.1 kardel return; 3532 1.1 kardel } 3533 1.1 kardel 3534 1.1 kardel unit = CLK_UNIT(parse->peer); 3535 1.1 kardel 3536 1.1 kardel /* 3537 1.1 kardel * handle changes 3538 1.1 kardel */ 3539 1.1 kardel parse_ctl(parse, in); 3540 1.15 christos 3541 1.1 kardel /* 3542 1.1 kardel * supply data 3543 1.1 kardel */ 3544 1.1 kardel if (out) 3545 1.1 kardel { 3546 1.1 kardel u_long sum = 0; 3547 1.1 kardel char *tt, *start; 3548 1.1 kardel int i; 3549 1.1 kardel 3550 1.1 kardel outstatus[0] = '\0'; 3551 1.1 kardel 3552 1.1 kardel out->type = REFCLK_PARSE; 3553 1.1 kardel 3554 1.1 kardel /* 3555 1.1 kardel * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3556 1.1 kardel */ 3557 1.1 kardel parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3558 1.1 kardel 3559 1.1 kardel /* 3560 1.1 kardel * figure out skew between PPS and RS232 - just for informational 3561 1.1 kardel * purposes 3562 1.1 kardel */ 3563 1.1 kardel if (PARSE_SYNC(parse->timedata.parse_state)) 3564 1.1 kardel { 3565 1.1 kardel if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 3566 1.1 kardel { 3567 1.1 kardel l_fp off; 3568 1.1 kardel 3569 1.1 kardel /* 3570 1.1 kardel * we have a PPS and RS232 signal - calculate the skew 3571 1.1 kardel * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 3572 1.1 kardel */ 3573 1.1 kardel off = parse->timedata.parse_stime.fp; 3574 1.1 kardel L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 3575 1.1 kardel tt = add_var(&out->kv_list, 80, RO); 3576 1.1 kardel snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 3577 1.1 kardel } 3578 1.1 kardel } 3579 1.1 kardel 3580 1.1 kardel if (PARSE_PPS(parse->timedata.parse_state)) 3581 1.1 kardel { 3582 1.1 kardel tt = add_var(&out->kv_list, 80, RO|DEF); 3583 1.1 kardel snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 3584 1.1 kardel } 3585 1.1 kardel 3586 1.1 kardel start = tt = add_var(&out->kv_list, 128, RO|DEF); 3587 1.6 christos tt = ap(start, 128, tt, "refclock_time=\""); 3588 1.1 kardel 3589 1.1 kardel if (parse->timedata.parse_time.fp.l_ui == 0) 3590 1.1 kardel { 3591 1.6 christos tt = ap(start, 128, tt, "<UNDEFINED>\""); 3592 1.1 kardel } 3593 1.1 kardel else 3594 1.1 kardel { 3595 1.6 christos tt = ap(start, 128, tt, "%s\"", 3596 1.6 christos gmprettydate(&parse->timedata.parse_time.fp)); 3597 1.1 kardel } 3598 1.1 kardel 3599 1.1 kardel if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3600 1.1 kardel { 3601 1.1 kardel ERR(ERR_INTERNAL) 3602 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 3603 1.1 kardel } 3604 1.1 kardel else 3605 1.1 kardel { 3606 1.1 kardel start = tt = add_var(&out->kv_list, 512, RO|DEF); 3607 1.6 christos tt = ap(start, 512, tt, "refclock_status=\""); 3608 1.1 kardel 3609 1.1 kardel /* 3610 1.1 kardel * copy PPS flags from last read transaction (informational only) 3611 1.1 kardel */ 3612 1.1 kardel tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 3613 1.1 kardel (PARSEB_PPS|PARSEB_S_PPS); 3614 1.1 kardel 3615 1.7 kardel (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 3616 1.7 kardel 3617 1.7 kardel tt += strlen(tt); 3618 1.1 kardel 3619 1.6 christos tt = ap(start, 512, tt, "\""); 3620 1.1 kardel 3621 1.1 kardel if (tmpctl.parsegettc.parse_count) 3622 1.1 kardel mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3623 1.1 kardel tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 3624 1.1 kardel 3625 1.1 kardel } 3626 1.15 christos 3627 1.1 kardel tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 3628 1.15 christos 3629 1.1 kardel if (!PARSE_GETFMT(parse, &tmpctl)) 3630 1.1 kardel { 3631 1.1 kardel ERR(ERR_INTERNAL) 3632 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 3633 1.1 kardel } 3634 1.1 kardel else 3635 1.1 kardel { 3636 1.21 christos int count = tmpctl.parseformat.parse_count; 3637 1.21 christos if (count) 3638 1.21 christos --count; 3639 1.7 kardel 3640 1.6 christos start = tt = add_var(&out->kv_list, 80, RO|DEF); 3641 1.6 christos tt = ap(start, 80, tt, "refclock_format=\""); 3642 1.1 kardel 3643 1.7 kardel if (count > 0) { 3644 1.15 christos tt = ap(start, 80, tt, "%*.*s", 3645 1.7 kardel count, 3646 1.7 kardel count, 3647 1.7 kardel tmpctl.parseformat.parse_buffer); 3648 1.7 kardel } 3649 1.7 kardel 3650 1.6 christos tt = ap(start, 80, tt, "\""); 3651 1.1 kardel } 3652 1.1 kardel 3653 1.1 kardel /* 3654 1.1 kardel * gather state statistics 3655 1.1 kardel */ 3656 1.1 kardel 3657 1.1 kardel start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3658 1.6 christos tt = ap(start, LEN_STATES, tt, "refclock_states=\""); 3659 1.1 kardel 3660 1.1 kardel for (i = 0; i <= CEVNT_MAX; i++) 3661 1.1 kardel { 3662 1.1 kardel u_long s_time; 3663 1.1 kardel u_long d = current_time - parse->generic->timestarted; 3664 1.1 kardel u_long percent; 3665 1.1 kardel 3666 1.1 kardel percent = s_time = PARSE_STATETIME(parse, i); 3667 1.1 kardel 3668 1.1 kardel while (((u_long)(~0) / 10000) < percent) 3669 1.1 kardel { 3670 1.1 kardel percent /= 10; 3671 1.1 kardel d /= 10; 3672 1.1 kardel } 3673 1.15 christos 3674 1.1 kardel if (d) 3675 1.1 kardel percent = (percent * 10000) / d; 3676 1.1 kardel else 3677 1.1 kardel percent = 10000; 3678 1.1 kardel 3679 1.1 kardel if (s_time) 3680 1.1 kardel { 3681 1.1 kardel char item[80]; 3682 1.1 kardel int count; 3683 1.15 christos 3684 1.1 kardel snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 3685 1.1 kardel sum ? "; " : "", 3686 1.1 kardel (parse->generic->currentstatus == i) ? "*" : "", 3687 1.1 kardel clockstatus((unsigned int)i), 3688 1.1 kardel l_mktime(s_time), 3689 1.1 kardel (int)(percent / 100), (int)(percent % 100)); 3690 1.15 christos if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start))) 3691 1.1 kardel { 3692 1.6 christos tt = ap(start, LEN_STATES, tt, 3693 1.6 christos "%s", item); 3694 1.1 kardel } 3695 1.1 kardel sum += s_time; 3696 1.1 kardel } 3697 1.1 kardel } 3698 1.15 christos 3699 1.20 christos ap(start, LEN_STATES, tt, "; running time: %s\"", l_mktime(sum)); 3700 1.15 christos 3701 1.1 kardel tt = add_var(&out->kv_list, 32, RO); 3702 1.1 kardel snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3703 1.15 christos 3704 1.1 kardel tt = add_var(&out->kv_list, 80, RO); 3705 1.1 kardel snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 3706 1.1 kardel 3707 1.1 kardel tt = add_var(&out->kv_list, 128, RO); 3708 1.1 kardel snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 3709 1.15 christos 3710 1.1 kardel { 3711 1.1 kardel struct ctl_var *k; 3712 1.15 christos 3713 1.1 kardel k = parse->kv; 3714 1.1 kardel while (k && !(k->flags & EOV)) 3715 1.1 kardel { 3716 1.1 kardel set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 3717 1.1 kardel k++; 3718 1.1 kardel } 3719 1.1 kardel } 3720 1.15 christos 3721 1.15 christos out->lencode = (u_short) strlen(outstatus); 3722 1.1 kardel out->p_lastcode = outstatus; 3723 1.1 kardel } 3724 1.1 kardel } 3725 1.1 kardel 3726 1.1 kardel /**=========================================================================== 3727 1.1 kardel ** processing routines 3728 1.1 kardel **/ 3729 1.1 kardel 3730 1.1 kardel /*-------------------------------------------------- 3731 1.1 kardel * event handling - note that nominal events will also be posted 3732 1.1 kardel * keep track of state dwelling times 3733 1.1 kardel */ 3734 1.1 kardel static void 3735 1.1 kardel parse_event( 3736 1.1 kardel struct parseunit *parse, 3737 1.1 kardel int event 3738 1.1 kardel ) 3739 1.1 kardel { 3740 1.1 kardel if (parse->generic->currentstatus != (u_char) event) 3741 1.1 kardel { 3742 1.1 kardel parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 3743 1.1 kardel parse->lastchange = current_time; 3744 1.1 kardel 3745 1.1 kardel if (parse->parse_type->cl_event) 3746 1.1 kardel parse->parse_type->cl_event(parse, event); 3747 1.10 christos 3748 1.1 kardel if (event == CEVNT_NOMINAL) 3749 1.1 kardel { 3750 1.1 kardel NLOG(NLOG_CLOCKSTATUS) 3751 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 3752 1.1 kardel CLK_UNIT(parse->peer)); 3753 1.1 kardel } 3754 1.1 kardel 3755 1.1 kardel refclock_report(parse->peer, event); 3756 1.1 kardel } 3757 1.1 kardel } 3758 1.1 kardel 3759 1.1 kardel /*-------------------------------------------------- 3760 1.1 kardel * process a PARSE time sample 3761 1.1 kardel */ 3762 1.1 kardel static void 3763 1.1 kardel parse_process( 3764 1.1 kardel struct parseunit *parse, 3765 1.1 kardel parsetime_t *parsetime 3766 1.1 kardel ) 3767 1.1 kardel { 3768 1.1 kardel l_fp off, rectime, reftime; 3769 1.1 kardel double fudge; 3770 1.15 christos 3771 1.10 christos /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */ 3772 1.10 christos ZERO(off); 3773 1.10 christos 3774 1.1 kardel /* 3775 1.1 kardel * check for changes in conversion status 3776 1.1 kardel * (only one for each new status !) 3777 1.1 kardel */ 3778 1.1 kardel if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 3779 1.1 kardel ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3780 1.1 kardel (parse->timedata.parse_status != parsetime->parse_status)) 3781 1.1 kardel { 3782 1.1 kardel char buffer[400]; 3783 1.15 christos 3784 1.1 kardel NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3785 1.1 kardel msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3786 1.1 kardel CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 3787 1.15 christos 3788 1.1 kardel if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 3789 1.1 kardel { 3790 1.1 kardel /* 3791 1.1 kardel * tell more about the story - list time code 3792 1.1 kardel * there is a slight change for a race condition and 3793 1.1 kardel * the time code might be overwritten by the next packet 3794 1.1 kardel */ 3795 1.1 kardel parsectl_t tmpctl; 3796 1.15 christos 3797 1.1 kardel if (!PARSE_GETTIMECODE(parse, &tmpctl)) 3798 1.1 kardel { 3799 1.1 kardel ERR(ERR_INTERNAL) 3800 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 3801 1.1 kardel } 3802 1.1 kardel else 3803 1.1 kardel { 3804 1.21 christos unsigned int count = tmpctl.parsegettc.parse_count; 3805 1.21 christos if (count) 3806 1.21 christos --count; 3807 1.1 kardel ERR(ERR_BADDATA) 3808 1.21 christos msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 3809 1.21 christos CLK_UNIT(parse->peer), 3810 1.21 christos mkascii(buffer, sizeof(buffer), 3811 1.21 christos tmpctl.parsegettc.parse_buffer, count)); 3812 1.1 kardel } 3813 1.16 christos /* copy status to show only changes in case of failures */ 3814 1.16 christos parse->timedata.parse_status = parsetime->parse_status; 3815 1.1 kardel } 3816 1.1 kardel } 3817 1.1 kardel 3818 1.1 kardel /* 3819 1.1 kardel * examine status and post appropriate events 3820 1.1 kardel */ 3821 1.1 kardel if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 3822 1.1 kardel { 3823 1.1 kardel /* 3824 1.1 kardel * got bad data - tell the rest of the system 3825 1.1 kardel */ 3826 1.1 kardel switch (parsetime->parse_status & CVT_MASK) 3827 1.1 kardel { 3828 1.1 kardel case CVT_NONE: 3829 1.1 kardel if ((parsetime->parse_status & CVT_ADDITIONAL) && 3830 1.1 kardel parse->parse_type->cl_message) 3831 1.1 kardel parse->parse_type->cl_message(parse, parsetime); 3832 1.1 kardel /* 3833 1.1 kardel * save PPS information that comes piggyback 3834 1.1 kardel */ 3835 1.1 kardel if (PARSE_PPS(parsetime->parse_state)) 3836 1.1 kardel { 3837 1.1 kardel parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3838 1.1 kardel parse->timedata.parse_ptime = parsetime->parse_ptime; 3839 1.1 kardel } 3840 1.1 kardel break; /* well, still waiting - timeout is handled at higher levels */ 3841 1.15 christos 3842 1.1 kardel case CVT_FAIL: 3843 1.1 kardel if (parsetime->parse_status & CVT_BADFMT) 3844 1.1 kardel { 3845 1.1 kardel parse_event(parse, CEVNT_BADREPLY); 3846 1.1 kardel } 3847 1.1 kardel else 3848 1.1 kardel if (parsetime->parse_status & CVT_BADDATE) 3849 1.1 kardel { 3850 1.1 kardel parse_event(parse, CEVNT_BADDATE); 3851 1.1 kardel } 3852 1.1 kardel else 3853 1.1 kardel if (parsetime->parse_status & CVT_BADTIME) 3854 1.1 kardel { 3855 1.1 kardel parse_event(parse, CEVNT_BADTIME); 3856 1.1 kardel } 3857 1.1 kardel else 3858 1.1 kardel { 3859 1.1 kardel parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 3860 1.1 kardel } 3861 1.1 kardel } 3862 1.1 kardel return; /* skip the rest - useless */ 3863 1.1 kardel } 3864 1.1 kardel 3865 1.1 kardel /* 3866 1.1 kardel * check for format changes 3867 1.1 kardel * (in case somebody has swapped clocks 8-) 3868 1.1 kardel */ 3869 1.1 kardel if (parse->lastformat != parsetime->parse_format) 3870 1.1 kardel { 3871 1.1 kardel parsectl_t tmpctl; 3872 1.15 christos 3873 1.1 kardel tmpctl.parseformat.parse_format = parsetime->parse_format; 3874 1.1 kardel 3875 1.1 kardel if (!PARSE_GETFMT(parse, &tmpctl)) 3876 1.1 kardel { 3877 1.1 kardel ERR(ERR_INTERNAL) 3878 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 3879 1.1 kardel } 3880 1.1 kardel else 3881 1.1 kardel { 3882 1.1 kardel NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3883 1.1 kardel msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 3884 1.1 kardel CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 3885 1.1 kardel } 3886 1.1 kardel parse->lastformat = parsetime->parse_format; 3887 1.1 kardel } 3888 1.1 kardel 3889 1.1 kardel /* 3890 1.1 kardel * now, any changes ? 3891 1.1 kardel */ 3892 1.1 kardel if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3893 1.1 kardel ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 3894 1.1 kardel { 3895 1.1 kardel char tmp1[200]; 3896 1.1 kardel char tmp2[200]; 3897 1.1 kardel /* 3898 1.1 kardel * something happend - except for PPS events 3899 1.1 kardel */ 3900 1.15 christos 3901 1.1 kardel (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3902 1.1 kardel (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 3903 1.15 christos 3904 1.1 kardel NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3905 1.1 kardel msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 3906 1.1 kardel CLK_UNIT(parse->peer), tmp2, tmp1); 3907 1.1 kardel } 3908 1.1 kardel 3909 1.1 kardel /* 3910 1.1 kardel * carry on PPS information if still usable 3911 1.1 kardel */ 3912 1.1 kardel if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3913 1.1 kardel { 3914 1.1 kardel parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3915 1.1 kardel parsetime->parse_ptime = parse->timedata.parse_ptime; 3916 1.1 kardel } 3917 1.1 kardel 3918 1.1 kardel /* 3919 1.1 kardel * remember for future 3920 1.1 kardel */ 3921 1.1 kardel parse->timedata = *parsetime; 3922 1.1 kardel 3923 1.1 kardel /* 3924 1.1 kardel * check to see, whether the clock did a complete powerup or lost PZF signal 3925 1.1 kardel * and post correct events for current condition 3926 1.1 kardel */ 3927 1.1 kardel if (PARSE_POWERUP(parsetime->parse_state)) 3928 1.1 kardel { 3929 1.1 kardel /* 3930 1.1 kardel * this is bad, as we have completely lost synchronisation 3931 1.1 kardel * well this is a problem with the receiver here 3932 1.1 kardel * for PARSE Meinberg DCF77 receivers the lost synchronisation 3933 1.1 kardel * is true as it is the powerup state and the time is taken 3934 1.1 kardel * from a crude real time clock chip 3935 1.5 kardel * for the PZF/GPS series this is only partly true, as 3936 1.1 kardel * PARSE_POWERUP only means that the pseudo random 3937 1.1 kardel * phase shift sequence cannot be found. this is only 3938 1.1 kardel * bad, if we have never seen the clock in the SYNC 3939 1.1 kardel * state, where the PHASE and EPOCH are correct. 3940 1.1 kardel * for reporting events the above business does not 3941 1.1 kardel * really matter, but we can use the time code 3942 1.1 kardel * even in the POWERUP state after having seen 3943 1.1 kardel * the clock in the synchronized state (PZF class 3944 1.1 kardel * receivers) unless we have had a telegram disruption 3945 1.1 kardel * after having seen the clock in the SYNC state. we 3946 1.1 kardel * thus require having seen the clock in SYNC state 3947 1.1 kardel * *after* having missed telegrams (noresponse) from 3948 1.1 kardel * the clock. one problem remains: we might use erroneously 3949 1.1 kardel * POWERUP data if the disruption is shorter than 1 polling 3950 1.1 kardel * interval. fortunately powerdowns last usually longer than 64 3951 1.1 kardel * seconds and the receiver is at least 2 minutes in the 3952 1.1 kardel * POWERUP or NOSYNC state before switching to SYNC 3953 1.5 kardel * for GPS receivers this can mean antenna problems and other causes. 3954 1.5 kardel * the additional grace period can be enables by a clock 3955 1.5 kardel * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set. 3956 1.1 kardel */ 3957 1.1 kardel parse_event(parse, CEVNT_FAULT); 3958 1.1 kardel NLOG(NLOG_CLOCKSTATUS) 3959 1.1 kardel ERR(ERR_BADSTATUS) 3960 1.5 kardel msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS", 3961 1.1 kardel CLK_UNIT(parse->peer)); 3962 1.1 kardel } 3963 1.1 kardel else 3964 1.1 kardel { 3965 1.1 kardel /* 3966 1.1 kardel * we have two states left 3967 1.1 kardel * 3968 1.1 kardel * SYNC: 3969 1.1 kardel * this state means that the EPOCH (timecode) and PHASE 3970 1.1 kardel * information has be read correctly (at least two 3971 1.1 kardel * successive PARSE timecodes were received correctly) 3972 1.1 kardel * this is the best possible state - full trust 3973 1.1 kardel * 3974 1.1 kardel * NOSYNC: 3975 1.1 kardel * The clock should be on phase with respect to the second 3976 1.1 kardel * signal, but the timecode has not been received correctly within 3977 1.1 kardel * at least the last two minutes. this is a sort of half baked state 3978 1.1 kardel * for PARSE Meinberg DCF77 clocks this is bad news (clock running 3979 1.1 kardel * without timecode confirmation) 3980 1.1 kardel * PZF 535 has also no time confirmation, but the phase should be 3981 1.1 kardel * very precise as the PZF signal can be decoded 3982 1.1 kardel */ 3983 1.1 kardel 3984 1.1 kardel if (PARSE_SYNC(parsetime->parse_state)) 3985 1.1 kardel { 3986 1.1 kardel /* 3987 1.1 kardel * currently completely synchronized - best possible state 3988 1.1 kardel */ 3989 1.1 kardel parse->lastsync = current_time; 3990 1.1 kardel clear_err(parse, ERR_BADSTATUS); 3991 1.1 kardel } 3992 1.1 kardel else 3993 1.1 kardel { 3994 1.1 kardel /* 3995 1.1 kardel * we have had some problems receiving the time code 3996 1.1 kardel */ 3997 1.1 kardel parse_event(parse, CEVNT_PROP); 3998 1.1 kardel NLOG(NLOG_CLOCKSTATUS) 3999 1.1 kardel ERR(ERR_BADSTATUS) 4000 1.1 kardel msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 4001 1.1 kardel CLK_UNIT(parse->peer)); 4002 1.1 kardel } 4003 1.1 kardel } 4004 1.1 kardel 4005 1.1 kardel fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 4006 1.15 christos 4007 1.1 kardel if (PARSE_TIMECODE(parsetime->parse_state)) 4008 1.1 kardel { 4009 1.1 kardel rectime = parsetime->parse_stime.fp; 4010 1.1 kardel off = reftime = parsetime->parse_time.fp; 4011 1.15 christos 4012 1.1 kardel L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 4013 1.1 kardel 4014 1.1 kardel #ifdef DEBUG 4015 1.1 kardel if (debug > 3) 4016 1.1 kardel printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 4017 1.1 kardel CLK_UNIT(parse->peer), 4018 1.1 kardel prettydate(&reftime), 4019 1.1 kardel prettydate(&rectime), 4020 1.1 kardel lfptoa(&off,6)); 4021 1.1 kardel #endif 4022 1.1 kardel } 4023 1.1 kardel 4024 1.1 kardel if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4025 1.1 kardel { 4026 1.1 kardel l_fp offset; 4027 1.1 kardel double ppsphaseadjust = parse->ppsphaseadjust; 4028 1.1 kardel 4029 1.1 kardel #ifdef HAVE_PPSAPI 4030 1.1 kardel /* 4031 1.1 kardel * set fudge = 0.0 if already included in PPS time stamps 4032 1.1 kardel */ 4033 1.1 kardel if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 4034 1.1 kardel { 4035 1.1 kardel ppsphaseadjust = 0.0; 4036 1.1 kardel } 4037 1.1 kardel #endif 4038 1.1 kardel 4039 1.1 kardel /* 4040 1.1 kardel * we have a PPS signal - much better than the RS232 stuff (we hope) 4041 1.1 kardel */ 4042 1.1 kardel offset = parsetime->parse_ptime.fp; 4043 1.1 kardel 4044 1.1 kardel #ifdef DEBUG 4045 1.1 kardel if (debug > 3) 4046 1.1 kardel printf("PARSE receiver #%d: PPStime %s\n", 4047 1.1 kardel CLK_UNIT(parse->peer), 4048 1.1 kardel prettydate(&offset)); 4049 1.1 kardel #endif 4050 1.1 kardel if (PARSE_TIMECODE(parsetime->parse_state)) 4051 1.1 kardel { 4052 1.10 christos if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) && 4053 1.10 christos M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf)) 4054 1.1 kardel { 4055 1.1 kardel fudge = ppsphaseadjust; /* pick PPS fudge factor */ 4056 1.15 christos 4057 1.1 kardel /* 4058 1.1 kardel * RS232 offsets within [-0.5..0.5[ - take PPS offsets 4059 1.1 kardel */ 4060 1.1 kardel 4061 1.1 kardel if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 4062 1.1 kardel { 4063 1.1 kardel reftime = off = offset; 4064 1.10 christos if (reftime.l_uf & 0x80000000) 4065 1.1 kardel reftime.l_ui++; 4066 1.1 kardel reftime.l_uf = 0; 4067 1.1 kardel 4068 1.15 christos 4069 1.1 kardel /* 4070 1.1 kardel * implied on second offset 4071 1.1 kardel */ 4072 1.1 kardel off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4073 1.15 christos off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 4074 1.1 kardel } 4075 1.1 kardel else 4076 1.1 kardel { 4077 1.1 kardel /* 4078 1.1 kardel * time code describes pulse 4079 1.1 kardel */ 4080 1.1 kardel reftime = off = parsetime->parse_time.fp; 4081 1.1 kardel 4082 1.1 kardel L_SUB(&off, &offset); /* true offset */ 4083 1.1 kardel } 4084 1.1 kardel } 4085 1.1 kardel /* 4086 1.1 kardel * take RS232 offset when PPS when out of bounds 4087 1.1 kardel */ 4088 1.1 kardel } 4089 1.1 kardel else 4090 1.1 kardel { 4091 1.1 kardel fudge = ppsphaseadjust; /* pick PPS fudge factor */ 4092 1.1 kardel /* 4093 1.1 kardel * Well, no time code to guide us - assume on second pulse 4094 1.1 kardel * and pray, that we are within [-0.5..0.5[ 4095 1.1 kardel */ 4096 1.1 kardel off = offset; 4097 1.1 kardel reftime = offset; 4098 1.10 christos if (reftime.l_uf & 0x80000000) 4099 1.1 kardel reftime.l_ui++; 4100 1.1 kardel reftime.l_uf = 0; 4101 1.1 kardel /* 4102 1.1 kardel * implied on second offset 4103 1.1 kardel */ 4104 1.1 kardel off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4105 1.10 christos off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 4106 1.1 kardel } 4107 1.1 kardel } 4108 1.1 kardel else 4109 1.1 kardel { 4110 1.1 kardel if (!PARSE_TIMECODE(parsetime->parse_state)) 4111 1.1 kardel { 4112 1.1 kardel /* 4113 1.1 kardel * Well, no PPS, no TIMECODE, no more work ... 4114 1.1 kardel */ 4115 1.1 kardel if ((parsetime->parse_status & CVT_ADDITIONAL) && 4116 1.1 kardel parse->parse_type->cl_message) 4117 1.1 kardel parse->parse_type->cl_message(parse, parsetime); 4118 1.1 kardel return; 4119 1.1 kardel } 4120 1.1 kardel } 4121 1.1 kardel 4122 1.1 kardel #ifdef DEBUG 4123 1.1 kardel if (debug > 3) 4124 1.1 kardel printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 4125 1.1 kardel CLK_UNIT(parse->peer), 4126 1.1 kardel prettydate(&reftime), 4127 1.1 kardel prettydate(&rectime), 4128 1.1 kardel lfptoa(&off,6)); 4129 1.1 kardel #endif 4130 1.1 kardel 4131 1.1 kardel 4132 1.1 kardel rectime = reftime; 4133 1.1 kardel L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 4134 1.15 christos 4135 1.1 kardel #ifdef DEBUG 4136 1.1 kardel if (debug > 3) 4137 1.1 kardel printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 4138 1.1 kardel CLK_UNIT(parse->peer), 4139 1.1 kardel prettydate(&reftime), 4140 1.1 kardel prettydate(&rectime)); 4141 1.1 kardel #endif 4142 1.1 kardel 4143 1.1 kardel if ((parsetime->parse_status & CVT_ADDITIONAL) && 4144 1.1 kardel parse->parse_type->cl_message) 4145 1.1 kardel parse->parse_type->cl_message(parse, parsetime); 4146 1.1 kardel 4147 1.1 kardel if (PARSE_SYNC(parsetime->parse_state)) 4148 1.1 kardel { 4149 1.1 kardel /* 4150 1.1 kardel * log OK status 4151 1.1 kardel */ 4152 1.1 kardel parse_event(parse, CEVNT_NOMINAL); 4153 1.1 kardel } 4154 1.1 kardel 4155 1.1 kardel clear_err(parse, ERR_BADIO); 4156 1.1 kardel clear_err(parse, ERR_BADDATA); 4157 1.1 kardel clear_err(parse, ERR_NODATA); 4158 1.1 kardel clear_err(parse, ERR_INTERNAL); 4159 1.15 christos 4160 1.1 kardel /* 4161 1.1 kardel * and now stick it into the clock machine 4162 1.1 kardel * samples are only valid iff lastsync is not too old and 4163 1.1 kardel * we have seen the clock in sync at least once 4164 1.1 kardel * after the last time we didn't see an expected data telegram 4165 1.1 kardel * at startup being not in sync is also bad just like 4166 1.15 christos * POWERUP state unless PARSE_F_POWERUPTRUST is set 4167 1.1 kardel * see the clock states section above for more reasoning 4168 1.1 kardel */ 4169 1.5 kardel if (((current_time - parse->lastsync) > parse->maxunsync) || 4170 1.5 kardel (parse->lastsync < parse->lastmissed) || 4171 1.1 kardel ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 4172 1.5 kardel (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) && 4173 1.5 kardel PARSE_POWERUP(parsetime->parse_state))) 4174 1.1 kardel { 4175 1.1 kardel parse->generic->leap = LEAP_NOTINSYNC; 4176 1.1 kardel parse->lastsync = 0; /* wait for full sync again */ 4177 1.1 kardel } 4178 1.1 kardel else 4179 1.1 kardel { 4180 1.1 kardel if (PARSE_LEAPADD(parsetime->parse_state)) 4181 1.1 kardel { 4182 1.1 kardel /* 4183 1.1 kardel * we pick this state also for time code that pass leap warnings 4184 1.1 kardel * without direction information (as earth is currently slowing 4185 1.1 kardel * down). 4186 1.1 kardel */ 4187 1.1 kardel parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 4188 1.1 kardel } 4189 1.1 kardel else 4190 1.1 kardel if (PARSE_LEAPDEL(parsetime->parse_state)) 4191 1.1 kardel { 4192 1.1 kardel parse->generic->leap = LEAP_DELSECOND; 4193 1.1 kardel } 4194 1.1 kardel else 4195 1.1 kardel { 4196 1.1 kardel parse->generic->leap = LEAP_NOWARNING; 4197 1.1 kardel } 4198 1.1 kardel } 4199 1.1 kardel 4200 1.1 kardel if (parse->generic->leap != LEAP_NOTINSYNC) 4201 1.1 kardel { 4202 1.1 kardel /* 4203 1.1 kardel * only good/trusted samples are interesting 4204 1.1 kardel */ 4205 1.1 kardel #ifdef DEBUG 4206 1.15 christos if (debug > 2) 4207 1.15 christos { 4208 1.15 christos printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 4209 1.1 kardel CLK_UNIT(parse->peer), 4210 1.1 kardel prettydate(&reftime), 4211 1.1 kardel prettydate(&rectime), 4212 1.1 kardel fudge); 4213 1.1 kardel } 4214 1.1 kardel #endif 4215 1.1 kardel parse->generic->lastref = reftime; 4216 1.15 christos 4217 1.1 kardel refclock_process_offset(parse->generic, reftime, rectime, fudge); 4218 1.1 kardel 4219 1.1 kardel #ifdef HAVE_PPSAPI 4220 1.1 kardel /* 4221 1.1 kardel * pass PPS information on to PPS clock 4222 1.1 kardel */ 4223 1.1 kardel if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4224 1.15 christos { 4225 1.15 christos parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS); 4226 1.1 kardel parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4227 1.1 kardel } 4228 1.1 kardel #endif 4229 1.1 kardel } else { 4230 1.15 christos parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4231 1.15 christos parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS); 4232 1.1 kardel } 4233 1.1 kardel 4234 1.1 kardel /* 4235 1.15 christos * ready, unless the machine wants a sample or 4236 1.1 kardel * we are in fast startup mode (peer->dist > MAXDISTANCE) 4237 1.1 kardel */ 4238 1.1 kardel if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 4239 1.1 kardel return; 4240 1.1 kardel 4241 1.1 kardel parse->pollneeddata = 0; 4242 1.1 kardel 4243 1.1 kardel parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4244 1.1 kardel 4245 1.1 kardel refclock_receive(parse->peer); 4246 1.1 kardel } 4247 1.15 christos 4248 1.1 kardel /**=========================================================================== 4249 1.1 kardel ** special code for special clocks 4250 1.1 kardel **/ 4251 1.1 kardel 4252 1.1 kardel static void 4253 1.1 kardel mk_utcinfo( 4254 1.20 christos char *t, /* pointer to the output string buffer */ 4255 1.20 christos uint16_t wnt, 4256 1.20 christos uint16_t wnlsf, 4257 1.1 kardel int dn, 4258 1.1 kardel int dtls, 4259 1.1 kardel int dtlsf, 4260 1.20 christos int size /* size of the output string buffer */ 4261 1.1 kardel ) 4262 1.1 kardel { 4263 1.15 christos /* 4264 1.15 christos * The week number transmitted by the GPS satellites for the leap date 4265 1.15 christos * is truncated to 8 bits only. If the nearest leap second date is off 4266 1.15 christos * the current date by more than +/- 128 weeks then conversion to a 4267 1.15 christos * calendar date is ambiguous. On the other hand, if a leap second is 4268 1.15 christos * currently being announced (i.e. dtlsf != dtls) then the week number 4269 1.15 christos * wnlsf is close enough, and we can unambiguously determine the date 4270 1.15 christos * for which the leap second is scheduled. 4271 1.15 christos */ 4272 1.15 christos if ( dtlsf != dtls ) 4273 1.15 christos { 4274 1.15 christos time_t t_ls; 4275 1.15 christos struct tm *tm; 4276 1.20 christos int nc; 4277 1.15 christos 4278 1.22 christos wnlsf = basedate_expand_gpsweek(wnlsf); 4279 1.20 christos /* 'wnt' not used here: would need the same treatment as 'wnlsf */ 4280 1.15 christos 4281 1.15 christos t_ls = (time_t) wnlsf * SECSPERWEEK 4282 1.15 christos + (time_t) dn * SECSPERDAY 4283 1.15 christos + GPS_SEC_BIAS - 1; 4284 1.15 christos 4285 1.15 christos tm = gmtime( &t_ls ); 4286 1.20 christos if (tm == NULL) /* gmtime() failed */ 4287 1.15 christos { 4288 1.15 christos snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" ); 4289 1.15 christos return; 4290 1.15 christos } 4291 1.15 christos 4292 1.20 christos nc = snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s", 4293 1.15 christos dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" ); 4294 1.20 christos if (nc < 0) 4295 1.20 christos nc = strlen(t); 4296 1.20 christos else if (nc > size) 4297 1.20 christos nc = size; 4298 1.20 christos 4299 1.20 christos snprintf( t + nc, size - nc, " at UTC midnight at the end of %s, %04i-%02i-%02i", 4300 1.15 christos daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday ); 4301 1.15 christos } 4302 1.15 christos else 4303 1.20 christos { 4304 1.23 kardel snprintf( t, size, "UTC offset parameter: %is, no leap second announced.", dtls ); 4305 1.20 christos } 4306 1.15 christos 4307 1.1 kardel } 4308 1.1 kardel 4309 1.1 kardel #ifdef CLOCK_MEINBERG 4310 1.1 kardel /**=========================================================================== 4311 1.15 christos ** Meinberg GPS receiver support 4312 1.1 kardel **/ 4313 1.1 kardel 4314 1.1 kardel /*------------------------------------------------------------ 4315 1.15 christos * gps16x_message - process messages from Meinberg GPS receiver 4316 1.1 kardel */ 4317 1.1 kardel static void 4318 1.1 kardel gps16x_message( 4319 1.1 kardel struct parseunit *parse, 4320 1.1 kardel parsetime_t *parsetime 4321 1.1 kardel ) 4322 1.1 kardel { 4323 1.1 kardel if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 4324 1.1 kardel { 4325 1.1 kardel GPS_MSG_HDR header; 4326 1.1 kardel unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 4327 1.15 christos 4328 1.1 kardel #ifdef DEBUG 4329 1.1 kardel if (debug > 2) 4330 1.1 kardel { 4331 1.1 kardel char msgbuffer[600]; 4332 1.15 christos 4333 1.1 kardel mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 4334 1.1 kardel printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 4335 1.1 kardel CLK_UNIT(parse->peer), 4336 1.1 kardel parsetime->parse_msglen, 4337 1.1 kardel msgbuffer); 4338 1.1 kardel } 4339 1.1 kardel #endif 4340 1.1 kardel get_mbg_header(&bufp, &header); 4341 1.15 christos if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 4342 1.15 christos (header.len == 0 || 4343 1.15 christos (header.len < sizeof(parsetime->parse_msg) && 4344 1.15 christos header.data_csum == mbg_csum(bufp, header.len)))) 4345 1.1 kardel { 4346 1.1 kardel /* 4347 1.1 kardel * clean message 4348 1.1 kardel */ 4349 1.15 christos switch (header.cmd) 4350 1.1 kardel { 4351 1.1 kardel case GPS_SW_REV: 4352 1.1 kardel { 4353 1.1 kardel char buffer[64]; 4354 1.1 kardel SW_REV gps_sw_rev; 4355 1.15 christos 4356 1.1 kardel get_mbg_sw_rev(&bufp, &gps_sw_rev); 4357 1.1 kardel snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 4358 1.1 kardel (gps_sw_rev.code >> 8) & 0xFF, 4359 1.1 kardel gps_sw_rev.code & 0xFF, 4360 1.1 kardel gps_sw_rev.name[0] ? " " : "", 4361 1.1 kardel gps_sw_rev.name); 4362 1.1 kardel set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4363 1.1 kardel } 4364 1.1 kardel break; 4365 1.1 kardel 4366 1.15 christos case GPS_BVAR_STAT: 4367 1.1 kardel { 4368 1.1 kardel static struct state 4369 1.1 kardel { 4370 1.15 christos BVAR_STAT flag; /* status flag */ 4371 1.15 christos const char *string; /* bit name */ 4372 1.1 kardel } states[] = 4373 1.1 kardel { 4374 1.15 christos { BVAR_CFGH_INVALID, "Configuration/Health" }, 4375 1.15 christos { BVAR_ALM_NOT_COMPLETE, "Almanachs" }, 4376 1.15 christos { BVAR_UTC_INVALID, "UTC Correction" }, 4377 1.15 christos { BVAR_IONO_INVALID, "Ionospheric Correction" }, 4378 1.15 christos { BVAR_RCVR_POS_INVALID, "Receiver Position" }, 4379 1.15 christos { 0, "" } 4380 1.1 kardel }; 4381 1.15 christos BVAR_STAT status; 4382 1.1 kardel struct state *s = states; 4383 1.1 kardel char buffer[512]; 4384 1.1 kardel char *p, *b; 4385 1.15 christos 4386 1.15 christos status = (BVAR_STAT) get_lsb_short(&bufp); 4387 1.6 christos p = b = buffer; 4388 1.6 christos p = ap(buffer, sizeof(buffer), p, 4389 1.6 christos "meinberg_gps_status=\"[0x%04x] ", 4390 1.6 christos status); 4391 1.15 christos 4392 1.1 kardel if (status) 4393 1.1 kardel { 4394 1.15 christos p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: "); 4395 1.6 christos b = p; 4396 1.1 kardel while (s->flag) 4397 1.1 kardel { 4398 1.1 kardel if (status & s->flag) 4399 1.1 kardel { 4400 1.1 kardel if (p != b) 4401 1.1 kardel { 4402 1.6 christos p = ap(buffer, sizeof(buffer), p, ", "); 4403 1.1 kardel } 4404 1.15 christos 4405 1.6 christos p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string); 4406 1.1 kardel } 4407 1.1 kardel s++; 4408 1.1 kardel } 4409 1.6 christos p = ap(buffer, sizeof(buffer), p, "\""); 4410 1.1 kardel } 4411 1.1 kardel else 4412 1.1 kardel { 4413 1.15 christos p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\""); 4414 1.1 kardel } 4415 1.15 christos 4416 1.1 kardel set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 4417 1.1 kardel } 4418 1.1 kardel break; 4419 1.1 kardel 4420 1.1 kardel case GPS_POS_XYZ: 4421 1.1 kardel { 4422 1.1 kardel XYZ xyz; 4423 1.1 kardel char buffer[256]; 4424 1.15 christos 4425 1.1 kardel get_mbg_xyz(&bufp, xyz); 4426 1.1 kardel snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 4427 1.1 kardel mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 4428 1.1 kardel mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 4429 1.1 kardel mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 4430 1.15 christos 4431 1.1 kardel set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4432 1.1 kardel } 4433 1.1 kardel break; 4434 1.15 christos 4435 1.1 kardel case GPS_POS_LLA: 4436 1.1 kardel { 4437 1.1 kardel LLA lla; 4438 1.1 kardel char buffer[256]; 4439 1.15 christos 4440 1.1 kardel get_mbg_lla(&bufp, lla); 4441 1.15 christos 4442 1.1 kardel snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 4443 1.1 kardel mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 4444 1.15 christos mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 4445 1.1 kardel mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 4446 1.15 christos 4447 1.1 kardel set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4448 1.1 kardel } 4449 1.1 kardel break; 4450 1.15 christos 4451 1.1 kardel case GPS_TZDL: 4452 1.1 kardel break; 4453 1.15 christos 4454 1.1 kardel case GPS_PORT_PARM: 4455 1.1 kardel break; 4456 1.15 christos 4457 1.1 kardel case GPS_SYNTH: 4458 1.1 kardel break; 4459 1.15 christos 4460 1.1 kardel case GPS_ANT_INFO: 4461 1.1 kardel { 4462 1.1 kardel ANT_INFO antinfo; 4463 1.1 kardel char buffer[512]; 4464 1.6 christos char *p, *q; 4465 1.15 christos 4466 1.1 kardel get_mbg_antinfo(&bufp, &antinfo); 4467 1.6 christos p = buffer; 4468 1.6 christos p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\""); 4469 1.1 kardel switch (antinfo.status) 4470 1.1 kardel { 4471 1.15 christos case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected 4472 1.6 christos p = ap(buffer, sizeof(buffer), 4473 1.6 christos p, "<OK>"); 4474 1.1 kardel break; 4475 1.15 christos 4476 1.15 christos case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set 4477 1.6 christos q = ap(buffer, sizeof(buffer), 4478 1.6 christos p, "DISCONNECTED since "); 4479 1.1 kardel NLOG(NLOG_CLOCKSTATUS) 4480 1.1 kardel ERR(ERR_BADSTATUS) 4481 1.1 kardel msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 4482 1.1 kardel CLK_UNIT(parse->peer), p); 4483 1.15 christos 4484 1.6 christos p = q; 4485 1.15 christos mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 4486 1.1 kardel *p = '\0'; 4487 1.1 kardel break; 4488 1.15 christos 4489 1.15 christos case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid 4490 1.6 christos p = ap(buffer, sizeof(buffer), 4491 1.15 christos p, "SYNC AFTER RECONNECT on "); 4492 1.15 christos mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0); 4493 1.6 christos p = ap(buffer, sizeof(buffer), 4494 1.15 christos p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ", 4495 1.1 kardel (antinfo.delta_t < 0) ? '-' : '+', 4496 1.15 christos (long) ABS(antinfo.delta_t) / 10000, 4497 1.15 christos (long) ABS(antinfo.delta_t) % 10000); 4498 1.15 christos mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 4499 1.1 kardel *p = '\0'; 4500 1.1 kardel break; 4501 1.15 christos 4502 1.1 kardel default: 4503 1.6 christos p = ap(buffer, sizeof(buffer), 4504 1.6 christos p, "bad status 0x%04x", 4505 1.6 christos antinfo.status); 4506 1.1 kardel break; 4507 1.1 kardel } 4508 1.15 christos 4509 1.6 christos p = ap(buffer, sizeof(buffer), p, "\""); 4510 1.15 christos 4511 1.6 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4512 1.1 kardel } 4513 1.1 kardel break; 4514 1.15 christos 4515 1.1 kardel case GPS_UCAP: 4516 1.1 kardel break; 4517 1.15 christos 4518 1.1 kardel case GPS_CFGH: 4519 1.1 kardel { 4520 1.1 kardel CFGH cfgh; 4521 1.1 kardel char buffer[512]; 4522 1.1 kardel char *p; 4523 1.15 christos 4524 1.1 kardel get_mbg_cfgh(&bufp, &cfgh); 4525 1.1 kardel if (cfgh.valid) 4526 1.1 kardel { 4527 1.15 christos const char *cp; 4528 1.15 christos uint16_t tmp_val; 4529 1.1 kardel int i; 4530 1.15 christos 4531 1.1 kardel p = buffer; 4532 1.6 christos p = ap(buffer, sizeof(buffer), 4533 1.6 christos p, "gps_tot_51=\""); 4534 1.1 kardel mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4535 1.6 christos p = ap(buffer, sizeof(buffer), 4536 1.6 christos p, "\""); 4537 1.15 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4538 1.15 christos 4539 1.1 kardel p = buffer; 4540 1.6 christos p = ap(buffer, sizeof(buffer), 4541 1.6 christos p, "gps_tot_63=\""); 4542 1.1 kardel mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4543 1.6 christos p = ap(buffer, sizeof(buffer), 4544 1.6 christos p, "\""); 4545 1.15 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4546 1.15 christos 4547 1.1 kardel p = buffer; 4548 1.6 christos p = ap(buffer, sizeof(buffer), 4549 1.6 christos p, "gps_t0a=\""); 4550 1.1 kardel mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4551 1.6 christos p = ap(buffer, sizeof(buffer), 4552 1.6 christos p, "\""); 4553 1.15 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4554 1.15 christos 4555 1.15 christos for (i = 0; i < N_SVNO_GPS; i++) 4556 1.1 kardel { 4557 1.1 kardel p = buffer; 4558 1.15 christos p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS); 4559 1.15 christos 4560 1.15 christos tmp_val = cfgh.health[i]; /* a 6 bit SV health code */ 4561 1.15 christos p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val); 4562 1.15 christos /* "All Ones" has a special meaning" */ 4563 1.15 christos if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */ 4564 1.15 christos cp = "SV UNAVAILABLE"; 4565 1.15 christos else { 4566 1.15 christos /* The MSB contains a summary of the 3 MSBs of the 8 bit health code, 4567 1.15 christos * indicating if the data sent by the satellite is OK or not. */ 4568 1.15 christos p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" ); 4569 1.15 christos 4570 1.15 christos /* The 5 LSBs contain the status of the different signals sent by the satellite. */ 4571 1.15 christos switch (tmp_val & 0x1F) 4572 1.15 christos { 4573 1.15 christos case 0x00: cp = "SIGNAL OK"; break; 4574 1.15 christos /* codes 0x01 through 0x1B indicate that one or more 4575 1.15 christos * specific signal components are weak or dead. 4576 1.15 christos * We don't decode this here in detail. */ 4577 1.15 christos case 0x1C: cp = "SV IS TEMP OUT"; break; 4578 1.15 christos case 0x1D: cp = "SV WILL BE TEMP OUT"; break; 4579 1.15 christos default: cp = "TRANSMISSION PROBLEMS"; break; 4580 1.15 christos } 4581 1.1 kardel } 4582 1.15 christos p = ap(buffer, sizeof(buffer), p, "%s)", cp ); 4583 1.15 christos 4584 1.15 christos tmp_val = cfgh.cfg[i]; /* a 4 bit SV configuration/type code */ 4585 1.15 christos p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val); 4586 1.15 christos switch (tmp_val & 0x7) 4587 1.1 kardel { 4588 1.15 christos case 0x00: cp = "(reserved)"; break; 4589 1.15 christos case 0x01: cp = "BLOCK II/IIA/IIR"; break; 4590 1.15 christos case 0x02: cp = "BLOCK IIR-M"; break; 4591 1.15 christos case 0x03: cp = "BLOCK IIF"; break; 4592 1.15 christos case 0x04: cp = "BLOCK III"; break; 4593 1.15 christos default: cp = "unknown SV type"; break; 4594 1.1 kardel } 4595 1.15 christos p = ap(buffer, sizeof(buffer), p, "%s", cp ); 4596 1.15 christos if (tmp_val & 0x08) /* A-S is on, P-code is encrypted */ 4597 1.15 christos p = ap( buffer, sizeof(buffer), p, ", A-S on" ); 4598 1.15 christos 4599 1.15 christos p = ap(buffer, sizeof(buffer), p, ")\""); 4600 1.15 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4601 1.1 kardel } 4602 1.1 kardel } 4603 1.1 kardel } 4604 1.1 kardel break; 4605 1.15 christos 4606 1.1 kardel case GPS_ALM: 4607 1.1 kardel break; 4608 1.15 christos 4609 1.1 kardel case GPS_EPH: 4610 1.1 kardel break; 4611 1.15 christos 4612 1.1 kardel case GPS_UTC: 4613 1.1 kardel { 4614 1.1 kardel UTC utc; 4615 1.1 kardel char buffer[512]; 4616 1.1 kardel char *p; 4617 1.15 christos 4618 1.1 kardel p = buffer; 4619 1.15 christos 4620 1.1 kardel get_mbg_utc(&bufp, &utc); 4621 1.15 christos 4622 1.1 kardel if (utc.valid) 4623 1.1 kardel { 4624 1.6 christos p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\""); 4625 1.7 kardel mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 4626 1.1 kardel p += strlen(p); 4627 1.6 christos p = ap(buffer, sizeof(buffer), p, "\""); 4628 1.1 kardel } 4629 1.1 kardel else 4630 1.1 kardel { 4631 1.6 christos p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\""); 4632 1.1 kardel } 4633 1.6 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4634 1.1 kardel } 4635 1.1 kardel break; 4636 1.15 christos 4637 1.1 kardel case GPS_IONO: 4638 1.1 kardel break; 4639 1.15 christos 4640 1.1 kardel case GPS_ASCII_MSG: 4641 1.1 kardel { 4642 1.1 kardel ASCII_MSG gps_ascii_msg; 4643 1.1 kardel char buffer[128]; 4644 1.15 christos 4645 1.1 kardel get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 4646 1.15 christos 4647 1.1 kardel if (gps_ascii_msg.valid) 4648 1.1 kardel { 4649 1.1 kardel char buffer1[128]; 4650 1.1 kardel mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 4651 1.15 christos 4652 1.1 kardel snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 4653 1.1 kardel } 4654 1.1 kardel else 4655 1.6 christos snprintf(buffer, sizeof(buffer), "gps_message=<NONE>"); 4656 1.15 christos 4657 1.6 christos set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 4658 1.1 kardel } 4659 1.15 christos 4660 1.1 kardel break; 4661 1.15 christos 4662 1.1 kardel default: 4663 1.1 kardel break; 4664 1.1 kardel } 4665 1.1 kardel } 4666 1.1 kardel else 4667 1.1 kardel { 4668 1.15 christos msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), " 4669 1.15 christos "data_len = %d, data_csum = 0x%x (expected 0x%x)", 4670 1.1 kardel CLK_UNIT(parse->peer), 4671 1.15 christos header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 4672 1.15 christos header.len, 4673 1.15 christos header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0))); 4674 1.1 kardel } 4675 1.1 kardel } 4676 1.15 christos 4677 1.1 kardel return; 4678 1.1 kardel } 4679 1.1 kardel 4680 1.1 kardel /*------------------------------------------------------------ 4681 1.1 kardel * gps16x_poll - query the reciver peridically 4682 1.1 kardel */ 4683 1.1 kardel static void 4684 1.1 kardel gps16x_poll( 4685 1.1 kardel struct peer *peer 4686 1.1 kardel ) 4687 1.1 kardel { 4688 1.10 christos struct parseunit *parse = peer->procptr->unitptr; 4689 1.15 christos 4690 1.15 christos static GPS_MSG_HDR sequence[] = 4691 1.1 kardel { 4692 1.1 kardel { GPS_SW_REV, 0, 0, 0 }, 4693 1.15 christos { GPS_BVAR_STAT, 0, 0, 0 }, 4694 1.1 kardel { GPS_UTC, 0, 0, 0 }, 4695 1.1 kardel { GPS_ASCII_MSG, 0, 0, 0 }, 4696 1.1 kardel { GPS_ANT_INFO, 0, 0, 0 }, 4697 1.1 kardel { GPS_CFGH, 0, 0, 0 }, 4698 1.1 kardel { GPS_POS_XYZ, 0, 0, 0 }, 4699 1.1 kardel { GPS_POS_LLA, 0, 0, 0 }, 4700 1.1 kardel { (unsigned short)~0, 0, 0, 0 } 4701 1.1 kardel }; 4702 1.10 christos 4703 1.1 kardel int rtc; 4704 1.1 kardel unsigned char cmd_buffer[64]; 4705 1.1 kardel unsigned char *outp = cmd_buffer; 4706 1.1 kardel GPS_MSG_HDR *header; 4707 1.15 christos 4708 1.1 kardel if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4709 1.1 kardel { 4710 1.10 christos parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4711 1.1 kardel } 4712 1.1 kardel 4713 1.15 christos if (sequence[parse->localstate].cmd == (unsigned short)~0) 4714 1.1 kardel parse->localstate = 0; 4715 1.15 christos 4716 1.1 kardel header = sequence + parse->localstate++; 4717 1.15 christos 4718 1.1 kardel *outp++ = SOH; /* start command */ 4719 1.15 christos 4720 1.1 kardel put_mbg_header(&outp, header); 4721 1.1 kardel outp = cmd_buffer + 1; 4722 1.15 christos 4723 1.15 christos header->hdr_csum = (short)mbg_csum(outp, 6); 4724 1.1 kardel put_mbg_header(&outp, header); 4725 1.15 christos 4726 1.1 kardel #ifdef DEBUG 4727 1.1 kardel if (debug > 2) 4728 1.1 kardel { 4729 1.1 kardel char buffer[128]; 4730 1.15 christos 4731 1.1 kardel mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 4732 1.1 kardel printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 4733 1.1 kardel CLK_UNIT(parse->peer), 4734 1.1 kardel parse->localstate - 1, 4735 1.1 kardel (int)(outp - cmd_buffer), 4736 1.15 christos buffer); 4737 1.1 kardel } 4738 1.1 kardel #endif 4739 1.15 christos 4740 1.15 christos rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4741 1.15 christos 4742 1.1 kardel if (rtc < 0) 4743 1.1 kardel { 4744 1.1 kardel ERR(ERR_BADIO) 4745 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4746 1.1 kardel } 4747 1.1 kardel else 4748 1.1 kardel if (rtc != outp - cmd_buffer) 4749 1.1 kardel { 4750 1.1 kardel ERR(ERR_BADIO) 4751 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer)); 4752 1.1 kardel } 4753 1.1 kardel 4754 1.1 kardel clear_err(parse, ERR_BADIO); 4755 1.1 kardel return; 4756 1.1 kardel } 4757 1.1 kardel 4758 1.1 kardel /*-------------------------------------------------- 4759 1.1 kardel * init routine - setup timer 4760 1.1 kardel */ 4761 1.1 kardel static int 4762 1.1 kardel gps16x_poll_init( 4763 1.1 kardel struct parseunit *parse 4764 1.1 kardel ) 4765 1.1 kardel { 4766 1.1 kardel if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4767 1.1 kardel { 4768 1.10 christos parse->peer->procptr->action = gps16x_poll; 4769 1.1 kardel gps16x_poll(parse->peer); 4770 1.1 kardel } 4771 1.1 kardel 4772 1.1 kardel return 0; 4773 1.1 kardel } 4774 1.1 kardel 4775 1.1 kardel #else 4776 1.1 kardel static void 4777 1.1 kardel gps16x_message( 4778 1.1 kardel struct parseunit *parse, 4779 1.1 kardel parsetime_t *parsetime 4780 1.1 kardel ) 4781 1.1 kardel {} 4782 1.1 kardel static int 4783 1.1 kardel gps16x_poll_init( 4784 1.1 kardel struct parseunit *parse 4785 1.1 kardel ) 4786 1.1 kardel { 4787 1.1 kardel return 1; 4788 1.1 kardel } 4789 1.1 kardel #endif /* CLOCK_MEINBERG */ 4790 1.15 christos 4791 1.1 kardel /**=========================================================================== 4792 1.1 kardel ** clock polling support 4793 1.1 kardel **/ 4794 1.1 kardel 4795 1.1 kardel /*-------------------------------------------------- 4796 1.1 kardel * direct poll routine 4797 1.1 kardel */ 4798 1.1 kardel static void 4799 1.1 kardel poll_dpoll( 4800 1.1 kardel struct parseunit *parse 4801 1.1 kardel ) 4802 1.1 kardel { 4803 1.15 christos long rtc; 4804 1.1 kardel const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 4805 1.15 christos long ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 4806 1.1 kardel 4807 1.15 christos rtc = write(parse->generic->io.fd, ps, ct); 4808 1.1 kardel if (rtc < 0) 4809 1.1 kardel { 4810 1.1 kardel ERR(ERR_BADIO) 4811 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4812 1.1 kardel } 4813 1.1 kardel else 4814 1.1 kardel if (rtc != ct) 4815 1.1 kardel { 4816 1.1 kardel ERR(ERR_BADIO) 4817 1.15 christos msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 4818 1.1 kardel } 4819 1.1 kardel clear_err(parse, ERR_BADIO); 4820 1.1 kardel } 4821 1.1 kardel 4822 1.1 kardel /*-------------------------------------------------- 4823 1.1 kardel * periodic poll routine 4824 1.1 kardel */ 4825 1.1 kardel static void 4826 1.1 kardel poll_poll( 4827 1.1 kardel struct peer *peer 4828 1.1 kardel ) 4829 1.1 kardel { 4830 1.10 christos struct parseunit *parse = peer->procptr->unitptr; 4831 1.15 christos 4832 1.1 kardel if (parse->parse_type->cl_poll) 4833 1.1 kardel parse->parse_type->cl_poll(parse); 4834 1.1 kardel 4835 1.1 kardel if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4836 1.1 kardel { 4837 1.10 christos parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 4838 1.1 kardel } 4839 1.1 kardel } 4840 1.1 kardel 4841 1.1 kardel /*-------------------------------------------------- 4842 1.1 kardel * init routine - setup timer 4843 1.1 kardel */ 4844 1.1 kardel static int 4845 1.1 kardel poll_init( 4846 1.1 kardel struct parseunit *parse 4847 1.1 kardel ) 4848 1.1 kardel { 4849 1.1 kardel if (((poll_info_t *)parse->parse_type->cl_data)->rate) 4850 1.1 kardel { 4851 1.10 christos parse->peer->procptr->action = poll_poll; 4852 1.1 kardel poll_poll(parse->peer); 4853 1.1 kardel } 4854 1.1 kardel 4855 1.1 kardel return 0; 4856 1.1 kardel } 4857 1.15 christos 4858 1.1 kardel /**=========================================================================== 4859 1.1 kardel ** Trimble support 4860 1.1 kardel **/ 4861 1.1 kardel 4862 1.1 kardel /*------------------------------------------------------------- 4863 1.1 kardel * trimble TAIP init routine - setup EOL and then do poll_init. 4864 1.1 kardel */ 4865 1.1 kardel static int 4866 1.1 kardel trimbletaip_init( 4867 1.1 kardel struct parseunit *parse 4868 1.1 kardel ) 4869 1.1 kardel { 4870 1.1 kardel #ifdef HAVE_TERMIOS 4871 1.1 kardel struct termios tio; 4872 1.1 kardel #endif 4873 1.1 kardel #ifdef HAVE_SYSV_TTYS 4874 1.1 kardel struct termio tio; 4875 1.1 kardel #endif 4876 1.1 kardel /* 4877 1.1 kardel * configure terminal line for trimble receiver 4878 1.1 kardel */ 4879 1.1 kardel if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 4880 1.1 kardel { 4881 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4882 1.1 kardel return 0; 4883 1.1 kardel } 4884 1.1 kardel else 4885 1.1 kardel { 4886 1.1 kardel tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4887 1.15 christos 4888 1.1 kardel if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 4889 1.1 kardel { 4890 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 4891 1.1 kardel return 0; 4892 1.1 kardel } 4893 1.1 kardel } 4894 1.1 kardel return poll_init(parse); 4895 1.1 kardel } 4896 1.1 kardel 4897 1.1 kardel /*-------------------------------------------------- 4898 1.1 kardel * trimble TAIP event routine - reset receiver upon data format trouble 4899 1.1 kardel */ 4900 1.1 kardel static const char *taipinit[] = { 4901 1.1 kardel ">FPV00000000<", 4902 1.1 kardel ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 4903 1.1 kardel ">FTM00020001<", 4904 1.1 kardel (char *)0 4905 1.1 kardel }; 4906 1.15 christos 4907 1.1 kardel static void 4908 1.1 kardel trimbletaip_event( 4909 1.1 kardel struct parseunit *parse, 4910 1.1 kardel int event 4911 1.1 kardel ) 4912 1.1 kardel { 4913 1.1 kardel switch (event) 4914 1.1 kardel { 4915 1.1 kardel case CEVNT_BADREPLY: /* reset on garbled input */ 4916 1.1 kardel case CEVNT_TIMEOUT: /* reset on no input */ 4917 1.1 kardel { 4918 1.1 kardel const char **iv; 4919 1.1 kardel 4920 1.1 kardel iv = taipinit; 4921 1.1 kardel while (*iv) 4922 1.1 kardel { 4923 1.15 christos int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv)); 4924 1.1 kardel if (rtc < 0) 4925 1.1 kardel { 4926 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 4927 1.1 kardel return; 4928 1.1 kardel } 4929 1.1 kardel else 4930 1.1 kardel { 4931 1.3 christos if (rtc != (int)strlen(*iv)) 4932 1.1 kardel { 4933 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 4934 1.1 kardel CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 4935 1.1 kardel return; 4936 1.1 kardel } 4937 1.1 kardel } 4938 1.1 kardel iv++; 4939 1.1 kardel } 4940 1.1 kardel 4941 1.1 kardel NLOG(NLOG_CLOCKINFO) 4942 1.1 kardel ERR(ERR_BADIO) 4943 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 4944 1.1 kardel CLK_UNIT(parse->peer)); 4945 1.1 kardel } 4946 1.1 kardel break; 4947 1.1 kardel 4948 1.1 kardel default: /* ignore */ 4949 1.1 kardel break; 4950 1.1 kardel } 4951 1.1 kardel } 4952 1.1 kardel 4953 1.1 kardel /* 4954 1.1 kardel * This driver supports the Trimble SVee Six Plus GPS receiver module. 4955 1.1 kardel * It should support other Trimble receivers which use the Trimble Standard 4956 1.1 kardel * Interface Protocol (see below). 4957 1.1 kardel * 4958 1.1 kardel * The module has a serial I/O port for command/data and a 1 pulse-per-second 4959 1.1 kardel * output, about 1 microsecond wide. The leading edge of the pulse is 4960 1.1 kardel * coincident with the change of the GPS second. This is the same as 4961 1.1 kardel * the change of the UTC second +/- ~1 microsecond. Some other clocks 4962 1.1 kardel * specifically use a feature in the data message as a timing reference, but 4963 1.1 kardel * the SVee Six Plus does not do this. In fact there is considerable jitter 4964 1.1 kardel * on the timing of the messages, so this driver only supports the use 4965 1.1 kardel * of the PPS pulse for accurate timing. Where it is determined that 4966 1.1 kardel * the offset is way off, when first starting up ntpd for example, 4967 1.1 kardel * the timing of the data stream is used until the offset becomes low enough 4968 1.1 kardel * (|offset| < CLOCK_MAX), at which point the pps offset is used. 4969 1.1 kardel * 4970 1.1 kardel * It can use either option for receiving PPS information - the 'ppsclock' 4971 1.1 kardel * stream pushed onto the serial data interface to timestamp the Carrier 4972 1.1 kardel * Detect interrupts, where the 1PPS connects to the CD line. This only 4973 1.1 kardel * works on SunOS 4.1.x currently. To select this, define PPSPPS in 4974 1.1 kardel * Config.local. The other option is to use a pulse-stretcher/level-converter 4975 1.1 kardel * to convert the PPS pulse into a RS232 start pulse & feed this into another 4976 1.1 kardel * tty port. To use this option, define PPSCLK in Config.local. The pps input, 4977 1.1 kardel * by whichever method, is handled in ntp_loopfilter.c 4978 1.1 kardel * 4979 1.1 kardel * The receiver uses a serial message protocol called Trimble Standard 4980 1.1 kardel * Interface Protocol (it can support others but this driver only supports 4981 1.1 kardel * TSIP). Messages in this protocol have the following form: 4982 1.1 kardel * 4983 1.1 kardel * <DLE><id> ... <data> ... <DLE><ETX> 4984 1.1 kardel * 4985 1.1 kardel * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 4986 1.1 kardel * on transmission and compressed back to one on reception. Otherwise 4987 1.1 kardel * the values of data bytes can be anything. The serial interface is RS-422 4988 1.1 kardel * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 4989 1.1 kardel * in total!), and 1 stop bit. The protocol supports byte, integer, single, 4990 1.1 kardel * and double datatypes. Integers are two bytes, sent most significant first. 4991 1.1 kardel * Singles are IEEE754 single precision floating point numbers (4 byte) sent 4992 1.1 kardel * sign & exponent first. Doubles are IEEE754 double precision floating point 4993 1.1 kardel * numbers (8 byte) sent sign & exponent first. 4994 1.1 kardel * The receiver supports a large set of messages, only a small subset of 4995 1.1 kardel * which are used here. From driver to receiver the following are used: 4996 1.1 kardel * 4997 1.1 kardel * ID Description 4998 1.1 kardel * 4999 1.1 kardel * 21 Request current time 5000 1.1 kardel * 22 Mode Select 5001 1.1 kardel * 2C Set/Request operating parameters 5002 1.1 kardel * 2F Request UTC info 5003 1.1 kardel * 35 Set/Request I/O options 5004 1.1 kardel 5005 1.1 kardel * From receiver to driver the following are recognised: 5006 1.1 kardel * 5007 1.1 kardel * ID Description 5008 1.1 kardel * 5009 1.1 kardel * 41 GPS Time 5010 1.1 kardel * 44 Satellite selection, PDOP, mode 5011 1.1 kardel * 46 Receiver health 5012 1.1 kardel * 4B Machine code/status 5013 1.1 kardel * 4C Report operating parameters (debug only) 5014 1.1 kardel * 4F UTC correction data (used to get leap second warnings) 5015 1.1 kardel * 55 I/O options (debug only) 5016 1.1 kardel * 5017 1.1 kardel * All others are accepted but ignored. 5018 1.1 kardel * 5019 1.1 kardel */ 5020 1.1 kardel 5021 1.1 kardel #define PI 3.1415926535898 /* lots of sig figs */ 5022 1.1 kardel #define D2R PI/180.0 5023 1.1 kardel 5024 1.1 kardel /*------------------------------------------------------------------- 5025 1.1 kardel * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 5026 1.1 kardel * interface to the receiver. 5027 1.1 kardel * 5028 1.1 kardel * CAVEAT: the sendflt, sendint routines are byte order dependend and 5029 1.1 kardel * float implementation dependend - these must be converted to portable 5030 1.1 kardel * versions ! 5031 1.1 kardel * 5032 1.1 kardel * CURRENT LIMITATION: float implementation. This runs only on systems 5033 1.1 kardel * with IEEE754 floats as native floats 5034 1.1 kardel */ 5035 1.1 kardel 5036 1.1 kardel typedef struct trimble 5037 1.1 kardel { 5038 1.1 kardel u_long last_msg; /* last message received */ 5039 1.1 kardel u_long last_reset; /* last time a reset was issued */ 5040 1.1 kardel u_char qtracking; /* query tracking status */ 5041 1.1 kardel u_long ctrack; /* current tracking set */ 5042 1.1 kardel u_long ltrack; /* last tracking set */ 5043 1.1 kardel } trimble_t; 5044 1.1 kardel 5045 1.1 kardel union uval { 5046 1.1 kardel u_char bd[8]; 5047 1.1 kardel int iv; 5048 1.1 kardel float fv; 5049 1.1 kardel double dv; 5050 1.1 kardel }; 5051 1.15 christos 5052 1.1 kardel struct txbuf 5053 1.1 kardel { 5054 1.1 kardel short idx; /* index to first unused byte */ 5055 1.1 kardel u_char *txt; /* pointer to actual data buffer */ 5056 1.1 kardel }; 5057 1.1 kardel 5058 1.15 christos void sendcmd (struct txbuf *buf, int c); 5059 1.15 christos void sendbyte (struct txbuf *buf, int b); 5060 1.15 christos void sendetx (struct txbuf *buf, struct parseunit *parse); 5061 1.15 christos void sendint (struct txbuf *buf, int a); 5062 1.15 christos void sendflt (struct txbuf *buf, double a); 5063 1.15 christos 5064 1.1 kardel void 5065 1.1 kardel sendcmd( 5066 1.1 kardel struct txbuf *buf, 5067 1.1 kardel int c 5068 1.1 kardel ) 5069 1.1 kardel { 5070 1.1 kardel buf->txt[0] = DLE; 5071 1.1 kardel buf->txt[1] = (u_char)c; 5072 1.1 kardel buf->idx = 2; 5073 1.1 kardel } 5074 1.1 kardel 5075 1.15 christos void sendcmd (struct txbuf *buf, int c); 5076 1.15 christos void sendbyte (struct txbuf *buf, int b); 5077 1.15 christos void sendetx (struct txbuf *buf, struct parseunit *parse); 5078 1.15 christos void sendint (struct txbuf *buf, int a); 5079 1.15 christos void sendflt (struct txbuf *buf, double a); 5080 1.15 christos 5081 1.1 kardel void 5082 1.1 kardel sendbyte( 5083 1.1 kardel struct txbuf *buf, 5084 1.1 kardel int b 5085 1.1 kardel ) 5086 1.1 kardel { 5087 1.1 kardel if (b == DLE) 5088 1.1 kardel buf->txt[buf->idx++] = DLE; 5089 1.1 kardel buf->txt[buf->idx++] = (u_char)b; 5090 1.1 kardel } 5091 1.1 kardel 5092 1.1 kardel void 5093 1.1 kardel sendetx( 5094 1.1 kardel struct txbuf *buf, 5095 1.1 kardel struct parseunit *parse 5096 1.1 kardel ) 5097 1.1 kardel { 5098 1.1 kardel buf->txt[buf->idx++] = DLE; 5099 1.1 kardel buf->txt[buf->idx++] = ETX; 5100 1.1 kardel 5101 1.1 kardel if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 5102 1.1 kardel { 5103 1.1 kardel ERR(ERR_BADIO) 5104 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 5105 1.1 kardel } 5106 1.1 kardel else 5107 1.1 kardel { 5108 1.1 kardel #ifdef DEBUG 5109 1.1 kardel if (debug > 2) 5110 1.1 kardel { 5111 1.1 kardel char buffer[256]; 5112 1.15 christos 5113 1.1 kardel mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 5114 1.1 kardel printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 5115 1.1 kardel CLK_UNIT(parse->peer), 5116 1.15 christos buf->idx, buffer); 5117 1.1 kardel } 5118 1.1 kardel #endif 5119 1.1 kardel clear_err(parse, ERR_BADIO); 5120 1.1 kardel } 5121 1.1 kardel } 5122 1.1 kardel 5123 1.15 christos void 5124 1.1 kardel sendint( 5125 1.1 kardel struct txbuf *buf, 5126 1.1 kardel int a 5127 1.1 kardel ) 5128 1.1 kardel { 5129 1.1 kardel /* send 16bit int, msbyte first */ 5130 1.1 kardel sendbyte(buf, (u_char)((a>>8) & 0xff)); 5131 1.1 kardel sendbyte(buf, (u_char)(a & 0xff)); 5132 1.1 kardel } 5133 1.1 kardel 5134 1.1 kardel void 5135 1.1 kardel sendflt( 5136 1.1 kardel struct txbuf *buf, 5137 1.1 kardel double a 5138 1.1 kardel ) 5139 1.1 kardel { 5140 1.1 kardel int i; 5141 1.1 kardel union uval uval; 5142 1.1 kardel 5143 1.15 christos uval.fv = (float) a; 5144 1.1 kardel #ifdef WORDS_BIGENDIAN 5145 1.1 kardel for (i=0; i<=3; i++) 5146 1.1 kardel #else 5147 1.1 kardel for (i=3; i>=0; i--) 5148 1.1 kardel #endif 5149 1.1 kardel sendbyte(buf, uval.bd[i]); 5150 1.1 kardel } 5151 1.1 kardel 5152 1.1 kardel #define TRIM_POS_OPT 0x13 /* output position with high precision */ 5153 1.1 kardel #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 5154 1.1 kardel 5155 1.1 kardel /*-------------------------------------------------- 5156 1.1 kardel * trimble TSIP setup routine 5157 1.1 kardel */ 5158 1.1 kardel static int 5159 1.1 kardel trimbletsip_setup( 5160 1.1 kardel struct parseunit *parse, 5161 1.1 kardel const char *reason 5162 1.1 kardel ) 5163 1.1 kardel { 5164 1.1 kardel u_char buffer[256]; 5165 1.1 kardel struct txbuf buf; 5166 1.1 kardel trimble_t *t = parse->localdata; 5167 1.1 kardel 5168 1.1 kardel if (t && t->last_reset && 5169 1.1 kardel ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 5170 1.1 kardel return 1; /* not yet */ 5171 1.1 kardel } 5172 1.1 kardel 5173 1.1 kardel if (t) 5174 1.1 kardel t->last_reset = current_time; 5175 1.15 christos 5176 1.1 kardel buf.txt = buffer; 5177 1.15 christos 5178 1.1 kardel sendcmd(&buf, CMD_CVERSION); /* request software versions */ 5179 1.1 kardel sendetx(&buf, parse); 5180 1.15 christos 5181 1.1 kardel sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 5182 1.1 kardel sendbyte(&buf, 4); /* static */ 5183 1.1 kardel sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 5184 1.1 kardel sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 5185 1.1 kardel sendflt(&buf, 12.0); /* PDOP mask = 12 */ 5186 1.1 kardel sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 5187 1.1 kardel sendetx(&buf, parse); 5188 1.15 christos 5189 1.1 kardel sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 5190 1.1 kardel sendbyte(&buf, 1); /* time transfer mode */ 5191 1.1 kardel sendetx(&buf, parse); 5192 1.15 christos 5193 1.1 kardel sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 5194 1.1 kardel sendetx(&buf, parse); 5195 1.15 christos 5196 1.1 kardel sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 5197 1.1 kardel sendbyte(&buf, 0x2); /* binary mode */ 5198 1.1 kardel sendetx(&buf, parse); 5199 1.15 christos 5200 1.1 kardel sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 5201 1.1 kardel sendbyte(&buf, TRIM_POS_OPT); /* position output */ 5202 1.1 kardel sendbyte(&buf, 0x00); /* no velocity output */ 5203 1.1 kardel sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 5204 1.1 kardel sendbyte(&buf, 0x00); /* no raw measurements */ 5205 1.1 kardel sendetx(&buf, parse); 5206 1.15 christos 5207 1.1 kardel sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 5208 1.1 kardel sendetx(&buf, parse); 5209 1.1 kardel 5210 1.1 kardel NLOG(NLOG_CLOCKINFO) 5211 1.1 kardel ERR(ERR_BADIO) 5212 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 5213 1.1 kardel 5214 1.1 kardel return 0; 5215 1.1 kardel } 5216 1.1 kardel 5217 1.1 kardel /*-------------------------------------------------- 5218 1.1 kardel * TRIMBLE TSIP check routine 5219 1.1 kardel */ 5220 1.1 kardel static void 5221 1.1 kardel trimble_check( 5222 1.1 kardel struct peer *peer 5223 1.1 kardel ) 5224 1.1 kardel { 5225 1.10 christos struct parseunit *parse = peer->procptr->unitptr; 5226 1.1 kardel trimble_t *t = parse->localdata; 5227 1.1 kardel u_char buffer[256]; 5228 1.1 kardel struct txbuf buf; 5229 1.1 kardel buf.txt = buffer; 5230 1.15 christos 5231 1.1 kardel if (t) 5232 1.1 kardel { 5233 1.1 kardel if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 5234 1.1 kardel (void)trimbletsip_setup(parse, "message timeout"); 5235 1.1 kardel } 5236 1.1 kardel 5237 1.1 kardel poll_poll(parse->peer); /* emit query string and re-arm timer */ 5238 1.15 christos 5239 1.1 kardel if (t && t->qtracking) 5240 1.1 kardel { 5241 1.1 kardel u_long oldsats = t->ltrack & ~t->ctrack; 5242 1.15 christos 5243 1.1 kardel t->qtracking = 0; 5244 1.1 kardel t->ltrack = t->ctrack; 5245 1.15 christos 5246 1.1 kardel if (oldsats) 5247 1.1 kardel { 5248 1.1 kardel int i; 5249 1.15 christos 5250 1.1 kardel for (i = 0; oldsats; i++) { 5251 1.1 kardel if (oldsats & (1 << i)) 5252 1.1 kardel { 5253 1.1 kardel sendcmd(&buf, CMD_CSTATTRACK); 5254 1.1 kardel sendbyte(&buf, i+1); /* old sat */ 5255 1.1 kardel sendetx(&buf, parse); 5256 1.1 kardel } 5257 1.1 kardel oldsats &= ~(1 << i); 5258 1.1 kardel } 5259 1.1 kardel } 5260 1.15 christos 5261 1.1 kardel sendcmd(&buf, CMD_CSTATTRACK); 5262 1.1 kardel sendbyte(&buf, 0x00); /* current tracking set */ 5263 1.1 kardel sendetx(&buf, parse); 5264 1.1 kardel } 5265 1.1 kardel } 5266 1.1 kardel 5267 1.1 kardel /*-------------------------------------------------- 5268 1.1 kardel * TRIMBLE TSIP end routine 5269 1.1 kardel */ 5270 1.1 kardel static void 5271 1.1 kardel trimbletsip_end( 5272 1.1 kardel struct parseunit *parse 5273 1.1 kardel ) 5274 1.1 kardel { trimble_t *t = parse->localdata; 5275 1.15 christos 5276 1.1 kardel if (t) 5277 1.1 kardel { 5278 1.1 kardel free(t); 5279 1.10 christos parse->localdata = NULL; 5280 1.1 kardel } 5281 1.10 christos parse->peer->procptr->nextaction = 0; 5282 1.10 christos parse->peer->procptr->action = NULL; 5283 1.1 kardel } 5284 1.1 kardel 5285 1.1 kardel /*-------------------------------------------------- 5286 1.1 kardel * TRIMBLE TSIP init routine 5287 1.1 kardel */ 5288 1.1 kardel static int 5289 1.1 kardel trimbletsip_init( 5290 1.1 kardel struct parseunit *parse 5291 1.1 kardel ) 5292 1.1 kardel { 5293 1.1 kardel #if defined(VEOL) || defined(VEOL2) 5294 1.1 kardel #ifdef HAVE_TERMIOS 5295 1.1 kardel struct termios tio; /* NEEDED FOR A LONG TIME ! */ 5296 1.1 kardel #endif 5297 1.1 kardel #ifdef HAVE_SYSV_TTYS 5298 1.1 kardel struct termio tio; /* NEEDED FOR A LONG TIME ! */ 5299 1.1 kardel #endif 5300 1.1 kardel /* 5301 1.1 kardel * allocate local data area 5302 1.1 kardel */ 5303 1.1 kardel if (!parse->localdata) 5304 1.1 kardel { 5305 1.1 kardel trimble_t *t; 5306 1.15 christos 5307 1.1 kardel t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 5308 1.15 christos 5309 1.1 kardel if (t) 5310 1.1 kardel { 5311 1.1 kardel memset((char *)t, 0, sizeof(trimble_t)); 5312 1.1 kardel t->last_msg = current_time; 5313 1.1 kardel } 5314 1.1 kardel } 5315 1.1 kardel 5316 1.10 christos parse->peer->procptr->action = trimble_check; 5317 1.10 christos parse->peer->procptr->nextaction = current_time; 5318 1.1 kardel 5319 1.1 kardel /* 5320 1.1 kardel * configure terminal line for ICANON mode with VEOL characters 5321 1.1 kardel */ 5322 1.1 kardel if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 5323 1.1 kardel { 5324 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 5325 1.1 kardel return 0; 5326 1.1 kardel } 5327 1.1 kardel else 5328 1.1 kardel { 5329 1.1 kardel if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 5330 1.1 kardel { 5331 1.1 kardel #ifdef VEOL 5332 1.1 kardel tio.c_cc[VEOL] = ETX; 5333 1.1 kardel #endif 5334 1.1 kardel #ifdef VEOL2 5335 1.1 kardel tio.c_cc[VEOL2] = DLE; 5336 1.1 kardel #endif 5337 1.1 kardel } 5338 1.1 kardel 5339 1.1 kardel if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 5340 1.1 kardel { 5341 1.1 kardel msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 5342 1.1 kardel return 0; 5343 1.1 kardel } 5344 1.1 kardel } 5345 1.1 kardel #endif 5346 1.1 kardel return trimbletsip_setup(parse, "initial startup"); 5347 1.1 kardel } 5348 1.1 kardel 5349 1.1 kardel /*------------------------------------------------------------ 5350 1.1 kardel * trimbletsip_event - handle Trimble events 5351 1.1 kardel * simple evente handler - attempt to re-initialize receiver 5352 1.1 kardel */ 5353 1.1 kardel static void 5354 1.1 kardel trimbletsip_event( 5355 1.1 kardel struct parseunit *parse, 5356 1.1 kardel int event 5357 1.1 kardel ) 5358 1.1 kardel { 5359 1.1 kardel switch (event) 5360 1.1 kardel { 5361 1.1 kardel case CEVNT_BADREPLY: /* reset on garbled input */ 5362 1.1 kardel case CEVNT_TIMEOUT: /* reset on no input */ 5363 1.1 kardel (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 5364 1.1 kardel break; 5365 1.1 kardel 5366 1.1 kardel default: /* ignore */ 5367 1.1 kardel break; 5368 1.1 kardel } 5369 1.1 kardel } 5370 1.1 kardel 5371 1.1 kardel /* 5372 1.1 kardel * getflt, getint convert fields in the incoming data into the 5373 1.1 kardel * appropriate type of item 5374 1.1 kardel * 5375 1.1 kardel * CAVEAT: these routines are currently definitely byte order dependent 5376 1.1 kardel * and assume Representation(float) == IEEE754 5377 1.1 kardel * These functions MUST be converted to portable versions (especially 5378 1.1 kardel * converting the float representation into ntp_fp formats in order 5379 1.1 kardel * to avoid floating point operations at all! 5380 1.1 kardel */ 5381 1.1 kardel 5382 1.1 kardel static float 5383 1.1 kardel getflt( 5384 1.1 kardel u_char *bp 5385 1.1 kardel ) 5386 1.1 kardel { 5387 1.1 kardel union uval uval; 5388 1.15 christos 5389 1.1 kardel #ifdef WORDS_BIGENDIAN 5390 1.1 kardel uval.bd[0] = *bp++; 5391 1.1 kardel uval.bd[1] = *bp++; 5392 1.1 kardel uval.bd[2] = *bp++; 5393 1.1 kardel uval.bd[3] = *bp; 5394 1.1 kardel #else /* ! WORDS_BIGENDIAN */ 5395 1.1 kardel uval.bd[3] = *bp++; 5396 1.1 kardel uval.bd[2] = *bp++; 5397 1.1 kardel uval.bd[1] = *bp++; 5398 1.1 kardel uval.bd[0] = *bp; 5399 1.1 kardel #endif /* ! WORDS_BIGENDIAN */ 5400 1.1 kardel return uval.fv; 5401 1.1 kardel } 5402 1.1 kardel 5403 1.1 kardel static double 5404 1.1 kardel getdbl( 5405 1.1 kardel u_char *bp 5406 1.1 kardel ) 5407 1.1 kardel { 5408 1.1 kardel union uval uval; 5409 1.15 christos 5410 1.1 kardel #ifdef WORDS_BIGENDIAN 5411 1.1 kardel uval.bd[0] = *bp++; 5412 1.1 kardel uval.bd[1] = *bp++; 5413 1.1 kardel uval.bd[2] = *bp++; 5414 1.1 kardel uval.bd[3] = *bp++; 5415 1.1 kardel uval.bd[4] = *bp++; 5416 1.1 kardel uval.bd[5] = *bp++; 5417 1.1 kardel uval.bd[6] = *bp++; 5418 1.1 kardel uval.bd[7] = *bp; 5419 1.1 kardel #else /* ! WORDS_BIGENDIAN */ 5420 1.1 kardel uval.bd[7] = *bp++; 5421 1.1 kardel uval.bd[6] = *bp++; 5422 1.1 kardel uval.bd[5] = *bp++; 5423 1.1 kardel uval.bd[4] = *bp++; 5424 1.1 kardel uval.bd[3] = *bp++; 5425 1.1 kardel uval.bd[2] = *bp++; 5426 1.1 kardel uval.bd[1] = *bp++; 5427 1.1 kardel uval.bd[0] = *bp; 5428 1.1 kardel #endif /* ! WORDS_BIGENDIAN */ 5429 1.1 kardel return uval.dv; 5430 1.1 kardel } 5431 1.1 kardel 5432 1.1 kardel static int 5433 1.1 kardel getshort( 5434 1.1 kardel unsigned char *p 5435 1.1 kardel ) 5436 1.1 kardel { 5437 1.15 christos return (int) get_msb_short(&p); 5438 1.1 kardel } 5439 1.1 kardel 5440 1.1 kardel /*-------------------------------------------------- 5441 1.1 kardel * trimbletsip_message - process trimble messages 5442 1.1 kardel */ 5443 1.1 kardel #define RTOD (180.0 / 3.1415926535898) 5444 1.1 kardel #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 5445 1.1 kardel 5446 1.1 kardel static void 5447 1.1 kardel trimbletsip_message( 5448 1.1 kardel struct parseunit *parse, 5449 1.1 kardel parsetime_t *parsetime 5450 1.1 kardel ) 5451 1.1 kardel { 5452 1.1 kardel unsigned char *buffer = parsetime->parse_msg; 5453 1.1 kardel unsigned int size = parsetime->parse_msglen; 5454 1.15 christos 5455 1.1 kardel if ((size < 4) || 5456 1.1 kardel (buffer[0] != DLE) || 5457 1.1 kardel (buffer[size-1] != ETX) || 5458 1.1 kardel (buffer[size-2] != DLE)) 5459 1.1 kardel { 5460 1.1 kardel #ifdef DEBUG 5461 1.1 kardel if (debug > 2) { 5462 1.3 christos size_t i; 5463 1.1 kardel 5464 1.1 kardel printf("TRIMBLE BAD packet, size %d:\n ", size); 5465 1.1 kardel for (i = 0; i < size; i++) { 5466 1.1 kardel printf ("%2.2x, ", buffer[i]&0xff); 5467 1.1 kardel if (i%16 == 15) printf("\n\t"); 5468 1.1 kardel } 5469 1.1 kardel printf("\n"); 5470 1.1 kardel } 5471 1.1 kardel #endif 5472 1.1 kardel return; 5473 1.1 kardel } 5474 1.1 kardel else 5475 1.1 kardel { 5476 1.15 christos u_short var_flag; 5477 1.1 kardel trimble_t *tr = parse->localdata; 5478 1.1 kardel unsigned int cmd = buffer[1]; 5479 1.1 kardel char pbuffer[200]; 5480 1.1 kardel char *t = pbuffer; 5481 1.1 kardel cmd_info_t *s; 5482 1.15 christos 5483 1.1 kardel #ifdef DEBUG 5484 1.1 kardel if (debug > 3) { 5485 1.3 christos size_t i; 5486 1.1 kardel 5487 1.1 kardel printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 5488 1.1 kardel for (i = 0; i < size; i++) { 5489 1.1 kardel printf ("%2.2x, ", buffer[i]&0xff); 5490 1.1 kardel if (i%16 == 15) printf("\n\t"); 5491 1.1 kardel } 5492 1.1 kardel printf("\n"); 5493 1.1 kardel } 5494 1.1 kardel #endif 5495 1.1 kardel 5496 1.1 kardel if (tr) 5497 1.1 kardel tr->last_msg = current_time; 5498 1.15 christos 5499 1.1 kardel s = trimble_convert(cmd, trimble_rcmds); 5500 1.15 christos 5501 1.1 kardel if (s) 5502 1.1 kardel { 5503 1.8 christos t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname); 5504 1.1 kardel } 5505 1.1 kardel else 5506 1.1 kardel { 5507 1.1 kardel DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 5508 1.1 kardel return; 5509 1.1 kardel } 5510 1.1 kardel 5511 1.15 christos var_flag = (u_short) s->varmode; 5512 1.1 kardel 5513 1.1 kardel switch(cmd) 5514 1.1 kardel { 5515 1.1 kardel case CMD_RCURTIME: 5516 1.8 christos t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f", 5517 1.1 kardel getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5518 1.1 kardel getflt((unsigned char *)&mb(6))); 5519 1.1 kardel break; 5520 1.15 christos 5521 1.1 kardel case CMD_RBEST4: 5522 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 5523 1.1 kardel switch (mb(0) & 0xF) 5524 1.1 kardel { 5525 1.1 kardel default: 5526 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, 5527 1.6 christos "0x%x", mb(0) & 0x7); 5528 1.1 kardel break; 5529 1.1 kardel 5530 1.1 kardel case 1: 5531 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "0D"); 5532 1.1 kardel break; 5533 1.15 christos 5534 1.1 kardel case 3: 5535 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 5536 1.1 kardel break; 5537 1.15 christos 5538 1.1 kardel case 4: 5539 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 5540 1.1 kardel break; 5541 1.1 kardel } 5542 1.1 kardel if (mb(0) & 0x10) 5543 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 5544 1.1 kardel else 5545 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5546 1.15 christos 5547 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 5548 1.1 kardel mb(1), mb(2), mb(3), mb(4), 5549 1.1 kardel getflt((unsigned char *)&mb(5)), 5550 1.1 kardel getflt((unsigned char *)&mb(9)), 5551 1.1 kardel getflt((unsigned char *)&mb(13)), 5552 1.1 kardel getflt((unsigned char *)&mb(17))); 5553 1.1 kardel 5554 1.1 kardel break; 5555 1.15 christos 5556 1.1 kardel case CMD_RVERSION: 5557 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)", 5558 1.1 kardel mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 5559 1.1 kardel break; 5560 1.15 christos 5561 1.1 kardel case CMD_RRECVHEALTH: 5562 1.1 kardel { 5563 1.1 kardel static const char *msgs[] = 5564 1.1 kardel { 5565 1.1 kardel "Battery backup failed", 5566 1.1 kardel "Signal processor error", 5567 1.1 kardel "Alignment error, channel or chip 1", 5568 1.1 kardel "Alignment error, channel or chip 2", 5569 1.1 kardel "Antenna feed line fault", 5570 1.1 kardel "Excessive ref freq. error", 5571 1.1 kardel "<BIT 6>", 5572 1.1 kardel "<BIT 7>" 5573 1.1 kardel }; 5574 1.15 christos 5575 1.1 kardel int i, bits; 5576 1.15 christos 5577 1.1 kardel switch (mb(0) & 0xFF) 5578 1.1 kardel { 5579 1.1 kardel default: 5580 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF); 5581 1.1 kardel break; 5582 1.1 kardel case 0x00: 5583 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes"); 5584 1.1 kardel break; 5585 1.1 kardel case 0x01: 5586 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet"); 5587 1.1 kardel break; 5588 1.1 kardel case 0x03: 5589 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high"); 5590 1.1 kardel break; 5591 1.1 kardel case 0x08: 5592 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites"); 5593 1.1 kardel break; 5594 1.1 kardel case 0x09: 5595 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite"); 5596 1.1 kardel break; 5597 1.1 kardel case 0x0A: 5598 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites"); 5599 1.1 kardel break; 5600 1.1 kardel case 0x0B: 5601 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites"); 5602 1.1 kardel break; 5603 1.1 kardel case 0x0C: 5604 1.12 joerg t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable"); 5605 1.1 kardel break; 5606 1.1 kardel } 5607 1.1 kardel 5608 1.1 kardel bits = mb(1) & 0xFF; 5609 1.15 christos 5610 1.1 kardel for (i = 0; i < 8; i++) 5611 1.1 kardel if (bits & (0x1<<i)) 5612 1.1 kardel { 5613 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 5614 1.1 kardel } 5615 1.1 kardel } 5616 1.1 kardel break; 5617 1.15 christos 5618 1.1 kardel case CMD_RMESSAGE: 5619 1.1 kardel mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 5620 1.1 kardel break; 5621 1.15 christos 5622 1.1 kardel case CMD_RMACHSTAT: 5623 1.1 kardel { 5624 1.1 kardel static const char *msgs[] = 5625 1.1 kardel { 5626 1.1 kardel "Synthesizer Fault", 5627 1.1 kardel "Battery Powered Time Clock Fault", 5628 1.1 kardel "A-to-D Converter Fault", 5629 1.1 kardel "The almanac stored in the receiver is not complete and current", 5630 1.1 kardel "<BIT 4>", 5631 1.1 kardel "<BIT 5", 5632 1.1 kardel "<BIT 6>", 5633 1.1 kardel "<BIT 7>" 5634 1.1 kardel }; 5635 1.15 christos 5636 1.1 kardel int i, bits; 5637 1.1 kardel 5638 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF); 5639 1.1 kardel bits = mb(1) & 0xFF; 5640 1.15 christos 5641 1.1 kardel for (i = 0; i < 8; i++) 5642 1.1 kardel if (bits & (0x1<<i)) 5643 1.1 kardel { 5644 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 5645 1.1 kardel } 5646 1.1 kardel 5647 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 5648 1.1 kardel } 5649 1.1 kardel break; 5650 1.15 christos 5651 1.1 kardel case CMD_ROPERPARAM: 5652 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f", 5653 1.1 kardel mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 5654 1.1 kardel getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 5655 1.1 kardel break; 5656 1.15 christos 5657 1.1 kardel case CMD_RUTCPARAM: 5658 1.1 kardel { 5659 1.1 kardel float t0t = getflt((unsigned char *)&mb(14)); 5660 1.15 christos short wnt = (short) getshort((unsigned char *)&mb(18)); 5661 1.15 christos short dtls = (short) getshort((unsigned char *)&mb(12)); 5662 1.15 christos short wnlsf = (short) getshort((unsigned char *)&mb(20)); 5663 1.15 christos short dn = (short) getshort((unsigned char *)&mb(22)); 5664 1.15 christos short dtlsf = (short) getshort((unsigned char *)&mb(24)); 5665 1.1 kardel 5666 1.1 kardel if ((int)t0t != 0) 5667 1.10 christos { 5668 1.10 christos mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5669 1.10 christos } 5670 1.1 kardel else 5671 1.10 christos { 5672 1.11 kardel t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>"); 5673 1.10 christos } 5674 1.1 kardel } 5675 1.1 kardel break; 5676 1.1 kardel 5677 1.1 kardel case CMD_RSAT1BIAS: 5678 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs", 5679 1.1 kardel getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 5680 1.1 kardel break; 5681 1.1 kardel 5682 1.1 kardel case CMD_RIOOPTIONS: 5683 1.1 kardel { 5684 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x", 5685 1.1 kardel mb(0), mb(1), mb(2), mb(3)); 5686 1.1 kardel if (mb(0) != TRIM_POS_OPT || 5687 1.1 kardel mb(2) != TRIM_TIME_OPT) 5688 1.1 kardel { 5689 1.1 kardel (void)trimbletsip_setup(parse, "bad io options"); 5690 1.1 kardel } 5691 1.1 kardel } 5692 1.1 kardel break; 5693 1.15 christos 5694 1.1 kardel case CMD_RSPOSXYZ: 5695 1.1 kardel { 5696 1.1 kardel double x = getflt((unsigned char *)&mb(0)); 5697 1.1 kardel double y = getflt((unsigned char *)&mb(4)); 5698 1.1 kardel double z = getflt((unsigned char *)&mb(8)); 5699 1.1 kardel double f = getflt((unsigned char *)&mb(12)); 5700 1.15 christos 5701 1.1 kardel if (f > 0.0) 5702 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 5703 1.1 kardel x, y, z, 5704 1.1 kardel f); 5705 1.1 kardel else 5706 1.10 christos return; 5707 1.1 kardel } 5708 1.1 kardel break; 5709 1.1 kardel 5710 1.1 kardel case CMD_RSLLAPOS: 5711 1.1 kardel { 5712 1.1 kardel double lat = getflt((unsigned char *)&mb(0)); 5713 1.1 kardel double lng = getflt((unsigned char *)&mb(4)); 5714 1.1 kardel double f = getflt((unsigned char *)&mb(12)); 5715 1.15 christos 5716 1.1 kardel if (f > 0.0) 5717 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm", 5718 1.1 kardel ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5719 1.1 kardel ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5720 1.1 kardel getflt((unsigned char *)&mb(8))); 5721 1.1 kardel else 5722 1.10 christos return; 5723 1.1 kardel } 5724 1.1 kardel break; 5725 1.1 kardel 5726 1.1 kardel case CMD_RDOUBLEXYZ: 5727 1.1 kardel { 5728 1.1 kardel double x = getdbl((unsigned char *)&mb(0)); 5729 1.1 kardel double y = getdbl((unsigned char *)&mb(8)); 5730 1.1 kardel double z = getdbl((unsigned char *)&mb(16)); 5731 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm", 5732 1.1 kardel x, y, z); 5733 1.1 kardel } 5734 1.1 kardel break; 5735 1.15 christos 5736 1.1 kardel case CMD_RDOUBLELLA: 5737 1.1 kardel { 5738 1.1 kardel double lat = getdbl((unsigned char *)&mb(0)); 5739 1.1 kardel double lng = getdbl((unsigned char *)&mb(8)); 5740 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm", 5741 1.1 kardel ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 5742 1.1 kardel ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 5743 1.1 kardel getdbl((unsigned char *)&mb(16))); 5744 1.1 kardel } 5745 1.1 kardel break; 5746 1.1 kardel 5747 1.1 kardel case CMD_RALLINVIEW: 5748 1.1 kardel { 5749 1.1 kardel int i, sats; 5750 1.15 christos 5751 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 5752 1.1 kardel switch (mb(0) & 0x7) 5753 1.1 kardel { 5754 1.1 kardel default: 5755 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7); 5756 1.1 kardel break; 5757 1.1 kardel 5758 1.1 kardel case 3: 5759 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 5760 1.1 kardel break; 5761 1.15 christos 5762 1.1 kardel case 4: 5763 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 5764 1.1 kardel break; 5765 1.1 kardel } 5766 1.1 kardel if (mb(0) & 0x8) 5767 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 5768 1.1 kardel else 5769 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5770 1.15 christos 5771 1.1 kardel sats = (mb(0)>>4) & 0xF; 5772 1.15 christos 5773 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 5774 1.1 kardel getflt((unsigned char *)&mb(1)), 5775 1.1 kardel getflt((unsigned char *)&mb(5)), 5776 1.1 kardel getflt((unsigned char *)&mb(9)), 5777 1.1 kardel getflt((unsigned char *)&mb(13)), 5778 1.1 kardel sats, (sats == 1) ? "" : "s"); 5779 1.1 kardel 5780 1.1 kardel for (i=0; i < sats; i++) 5781 1.1 kardel { 5782 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i)); 5783 1.1 kardel if (tr) 5784 1.1 kardel tr->ctrack |= (1 << (mb(17+i)-1)); 5785 1.1 kardel } 5786 1.1 kardel 5787 1.1 kardel if (tr) 5788 1.10 christos { /* mark for tracking status query */ 5789 1.1 kardel tr->qtracking = 1; 5790 1.1 kardel } 5791 1.1 kardel } 5792 1.1 kardel break; 5793 1.15 christos 5794 1.1 kardel case CMD_RSTATTRACK: 5795 1.1 kardel { 5796 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 5797 1.1 kardel if (getflt((unsigned char *)&mb(4)) < 0.0) 5798 1.1 kardel { 5799 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>"); 5800 1.15 christos var_flag &= (u_short)(~DEF); 5801 1.1 kardel } 5802 1.1 kardel else 5803 1.15 christos { 5804 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 5805 1.1 kardel (mb(1) & 0xFF)>>3, 5806 1.1 kardel mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 5807 1.1 kardel mb(3), 5808 1.1 kardel getflt((unsigned char *)&mb(4)), 5809 1.1 kardel getflt((unsigned char *)&mb(12)) * RTOD, 5810 1.1 kardel getflt((unsigned char *)&mb(16)) * RTOD); 5811 1.1 kardel if (mb(20)) 5812 1.1 kardel { 5813 1.15 christos var_flag &= (u_short)(~DEF); 5814 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", OLD"); 5815 1.1 kardel } 5816 1.1 kardel if (mb(22)) 5817 1.1 kardel { 5818 1.1 kardel if (mb(22) == 1) 5819 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY"); 5820 1.1 kardel else 5821 1.1 kardel if (mb(22) == 2) 5822 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH"); 5823 1.1 kardel } 5824 1.1 kardel if (mb(23)) 5825 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data"); 5826 1.1 kardel } 5827 1.1 kardel } 5828 1.1 kardel break; 5829 1.15 christos 5830 1.1 kardel default: 5831 1.6 christos t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>"); 5832 1.1 kardel break; 5833 1.1 kardel } 5834 1.1 kardel 5835 1.15 christos t = ap(pbuffer, sizeof(pbuffer), t, "\""); 5836 1.1 kardel set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 5837 1.1 kardel } 5838 1.1 kardel } 5839 1.1 kardel 5840 1.15 christos 5841 1.1 kardel /**============================================================ 5842 1.1 kardel ** RAWDCF support 5843 1.1 kardel **/ 5844 1.1 kardel 5845 1.1 kardel /*-------------------------------------------------- 5846 1.1 kardel * rawdcf_init_1 - set up modem lines for RAWDCF receivers 5847 1.1 kardel * SET DTR line 5848 1.1 kardel */ 5849 1.1 kardel #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 5850 1.1 kardel static int 5851 1.1 kardel rawdcf_init_1( 5852 1.1 kardel struct parseunit *parse 5853 1.1 kardel ) 5854 1.1 kardel { 5855 1.1 kardel /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp (at) bszh.de> */ 5856 1.1 kardel /* 5857 1.1 kardel * You can use the RS232 to supply the power for a DCF77 receiver. 5858 1.1 kardel * Here a voltage between the DTR and the RTS line is used. Unfortunately 5859 1.1 kardel * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5860 1.1 kardel */ 5861 1.1 kardel int sl232; 5862 1.1 kardel 5863 1.1 kardel if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 5864 1.1 kardel { 5865 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5866 1.1 kardel return 0; 5867 1.1 kardel } 5868 1.1 kardel 5869 1.1 kardel #ifdef TIOCM_DTR 5870 1.1 kardel sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 5871 1.1 kardel #else 5872 1.1 kardel sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 5873 1.1 kardel #endif 5874 1.1 kardel 5875 1.1 kardel if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5876 1.1 kardel { 5877 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 5878 1.1 kardel } 5879 1.1 kardel return 0; 5880 1.1 kardel } 5881 1.1 kardel #else 5882 1.1 kardel static int 5883 1.1 kardel rawdcfdtr_init_1( 5884 1.1 kardel struct parseunit *parse 5885 1.1 kardel ) 5886 1.1 kardel { 5887 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 5888 1.1 kardel return 0; 5889 1.1 kardel } 5890 1.1 kardel #endif /* DTR initialisation type */ 5891 1.1 kardel 5892 1.1 kardel /*-------------------------------------------------- 5893 1.1 kardel * rawdcf_init_2 - set up modem lines for RAWDCF receivers 5894 1.1 kardel * CLR DTR line, SET RTS line 5895 1.1 kardel */ 5896 1.1 kardel #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 5897 1.1 kardel static int 5898 1.1 kardel rawdcf_init_2( 5899 1.1 kardel struct parseunit *parse 5900 1.1 kardel ) 5901 1.1 kardel { 5902 1.1 kardel /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp (at) bszh.de> */ 5903 1.1 kardel /* 5904 1.1 kardel * You can use the RS232 to supply the power for a DCF77 receiver. 5905 1.1 kardel * Here a voltage between the DTR and the RTS line is used. Unfortunately 5906 1.1 kardel * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 5907 1.1 kardel */ 5908 1.1 kardel int sl232; 5909 1.1 kardel 5910 1.1 kardel if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 5911 1.1 kardel { 5912 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5913 1.1 kardel return 0; 5914 1.1 kardel } 5915 1.1 kardel 5916 1.1 kardel #ifdef TIOCM_RTS 5917 1.1 kardel sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 5918 1.1 kardel #else 5919 1.1 kardel sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 5920 1.1 kardel #endif 5921 1.1 kardel 5922 1.1 kardel if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 5923 1.1 kardel { 5924 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 5925 1.1 kardel } 5926 1.1 kardel return 0; 5927 1.1 kardel } 5928 1.1 kardel #else 5929 1.1 kardel static int 5930 1.1 kardel rawdcf_init_2( 5931 1.1 kardel struct parseunit *parse 5932 1.1 kardel ) 5933 1.1 kardel { 5934 1.1 kardel msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 5935 1.1 kardel return 0; 5936 1.1 kardel } 5937 1.1 kardel #endif /* DTR initialisation type */ 5938 1.1 kardel 5939 1.1 kardel #else /* defined(REFCLOCK) && defined(PARSE) */ 5940 1.10 christos NONEMPTY_TRANSLATION_UNIT 5941 1.1 kardel #endif /* defined(REFCLOCK) && defined(PARSE) */ 5942 1.1 kardel 5943 1.1 kardel /* 5944 1.1 kardel * History: 5945 1.1 kardel * 5946 1.1 kardel * refclock_parse.c,v 5947 1.1 kardel * Revision 4.81 2009/05/01 10:15:29 kardel 5948 1.1 kardel * use new refclock_ppsapi interface 5949 1.1 kardel * 5950 1.1 kardel * Revision 4.80 2007/08/11 12:06:29 kardel 5951 1.1 kardel * update comments wrt/ to PPS 5952 1.1 kardel * 5953 1.1 kardel * Revision 4.79 2007/08/11 11:52:23 kardel 5954 1.1 kardel * - terminate io bindings before io_closeclock() will close our file descriptor 5955 1.1 kardel * 5956 1.1 kardel * Revision 4.78 2006/12/22 20:08:27 kardel 5957 1.1 kardel * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5958 1.1 kardel * 5959 1.1 kardel * Revision 4.77 2006/08/05 07:44:49 kardel 5960 1.1 kardel * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5961 1.1 kardel * 5962 1.1 kardel * Revision 4.76 2006/06/22 18:40:47 kardel 5963 1.1 kardel * clean up signedness (gcc 4) 5964 1.1 kardel * 5965 1.1 kardel * Revision 4.75 2006/06/22 16:58:10 kardel 5966 1.1 kardel * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5967 1.1 kardel * the PPS offset. Fix sign of offset passed to kernel. 5968 1.1 kardel * 5969 1.1 kardel * Revision 4.74 2006/06/18 21:18:37 kardel 5970 1.1 kardel * NetBSD Coverity CID 3796: possible NULL deref 5971 1.1 kardel * 5972 1.1 kardel * Revision 4.73 2006/05/26 14:23:46 kardel 5973 1.1 kardel * cleanup of copyright info 5974 1.1 kardel * 5975 1.1 kardel * Revision 4.72 2006/05/26 14:19:43 kardel 5976 1.1 kardel * cleanup of ioctl cruft 5977 1.1 kardel * 5978 1.1 kardel * Revision 4.71 2006/05/26 14:15:57 kardel 5979 1.1 kardel * delay adding refclock to async refclock io after all initializations 5980 1.1 kardel * 5981 1.1 kardel * Revision 4.70 2006/05/25 18:20:50 kardel 5982 1.1 kardel * bug #619 5983 1.1 kardel * terminate parse io engine after de-registering 5984 1.1 kardel * from refclock io engine 5985 1.1 kardel * 5986 1.1 kardel * Revision 4.69 2006/05/25 17:28:02 kardel 5987 1.1 kardel * complete refclock io structure initialization *before* inserting it into the 5988 1.1 kardel * refclock input machine (avoids null pointer deref) (bug #619) 5989 1.1 kardel * 5990 1.1 kardel * Revision 4.68 2006/05/01 17:02:51 kardel 5991 1.1 kardel * copy receiver method also for newlwy created receive buffers 5992 1.1 kardel * 5993 1.1 kardel * Revision 4.67 2006/05/01 14:37:29 kardel 5994 1.1 kardel * If an input buffer parses into more than one message do insert the 5995 1.1 kardel * parsed message in a new input buffer instead of processing it 5996 1.1 kardel * directly. This avoids deed complicated processing in signal 5997 1.1 kardel * handling. 5998 1.1 kardel * 5999 1.1 kardel * Revision 4.66 2006/03/18 00:45:30 kardel 6000 1.1 kardel * coverity fixes found in NetBSD coverity scan 6001 1.1 kardel * 6002 1.1 kardel * Revision 4.65 2006/01/26 06:08:33 kardel 6003 1.1 kardel * output errno on PPS setup failure 6004 1.1 kardel * 6005 1.1 kardel * Revision 4.64 2005/11/09 20:44:47 kardel 6006 1.1 kardel * utilize full PPS timestamp resolution from PPS API 6007 1.1 kardel * 6008 1.1 kardel * Revision 4.63 2005/10/07 22:10:25 kardel 6009 1.1 kardel * bounded buffer implementation 6010 1.1 kardel * 6011 1.1 kardel * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 6012 1.1 kardel * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 6013 1.1 kardel * replace almost all str* and *printf functions be their buffer bounded 6014 1.1 kardel * counterparts 6015 1.1 kardel * 6016 1.1 kardel * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 6017 1.1 kardel * limit re-set rate of trimble clocks 6018 1.1 kardel * 6019 1.1 kardel * Revision 4.62 2005/08/06 17:40:00 kardel 6020 1.1 kardel * cleanup size handling wrt/ to buffer boundaries 6021 1.1 kardel * 6022 1.1 kardel * Revision 4.61 2005/07/27 21:16:19 kardel 6023 1.1 kardel * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 6024 1.1 kardel * default setup. CSTOPB was missing for the 7E2 default data format of 6025 1.1 kardel * the DCF77 clocks. 6026 1.1 kardel * 6027 1.1 kardel * Revision 4.60 2005/07/17 21:14:44 kardel 6028 1.1 kardel * change contents of version string to include the RCS/CVS Id 6029 1.1 kardel * 6030 1.1 kardel * Revision 4.59 2005/07/06 06:56:38 kardel 6031 1.1 kardel * syntax error 6032 1.1 kardel * 6033 1.1 kardel * Revision 4.58 2005/07/04 13:10:40 kardel 6034 1.1 kardel * fix bug 455: tripping over NULL pointer on cleanup 6035 1.1 kardel * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 6036 1.1 kardel * fix compiler warnings for some platforms wrt/ printf formatstrings and 6037 1.1 kardel * varying structure element sizes 6038 1.1 kardel * reorder assignment in binding to avoid tripping over NULL pointers 6039 1.1 kardel * 6040 1.1 kardel * Revision 4.57 2005/06/25 09:25:19 kardel 6041 1.1 kardel * sort out log output sequence 6042 1.1 kardel * 6043 1.1 kardel * Revision 4.56 2005/06/14 21:47:27 kardel 6044 1.1 kardel * collect samples only if samples are ok (sync or trusted flywheel) 6045 1.1 kardel * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 6046 1.1 kardel * en- and dis-able HARDPPS in correlation to receiver sync state 6047 1.1 kardel * 6048 1.1 kardel * Revision 4.55 2005/06/02 21:28:31 kardel 6049 1.1 kardel * clarify trust logic 6050 1.1 kardel * 6051 1.1 kardel * Revision 4.54 2005/06/02 17:06:49 kardel 6052 1.1 kardel * change status reporting to use fixed refclock_report() 6053 1.1 kardel * 6054 1.1 kardel * Revision 4.53 2005/06/02 16:33:31 kardel 6055 1.1 kardel * fix acceptance of clocks unsync clocks right at start 6056 1.1 kardel * 6057 1.1 kardel * Revision 4.52 2005/05/26 21:55:06 kardel 6058 1.1 kardel * cleanup status reporting 6059 1.1 kardel * 6060 1.1 kardel * Revision 4.51 2005/05/26 19:19:14 kardel 6061 1.1 kardel * implement fast refclock startup 6062 1.1 kardel * 6063 1.1 kardel * Revision 4.50 2005/04/16 20:51:35 kardel 6064 1.13 christos * set hardpps_enable = 1 when binding a kernel PPS source 6065 1.1 kardel * 6066 1.1 kardel * Revision 4.49 2005/04/16 17:29:26 kardel 6067 1.1 kardel * add non polling clock type 18 for just listenning to Meinberg clocks 6068 1.1 kardel * 6069 1.1 kardel * Revision 4.48 2005/04/16 16:22:27 kardel 6070 1.1 kardel * bk sync 20050415 ntp-dev 6071 1.1 kardel * 6072 1.1 kardel * Revision 4.47 2004/11/29 10:42:48 kardel 6073 1.1 kardel * bk sync ntp-dev 20041129 6074 1.1 kardel * 6075 1.1 kardel * Revision 4.46 2004/11/29 10:26:29 kardel 6076 1.1 kardel * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 6077 1.1 kardel * 6078 1.1 kardel * Revision 4.45 2004/11/14 20:53:20 kardel 6079 1.1 kardel * clear PPS flags after using them 6080 1.1 kardel * 6081 1.1 kardel * Revision 4.44 2004/11/14 15:29:41 kardel 6082 1.1 kardel * support PPSAPI, upgrade Copyright to Berkeley style 6083 1.1 kardel * 6084 1.1 kardel * Revision 4.43 2001/05/26 22:53:16 kardel 6085 1.1 kardel * 20010526 reconcilation 6086 1.1 kardel * 6087 1.1 kardel * Revision 4.42 2000/05/14 15:31:51 kardel 6088 1.1 kardel * PPSAPI && RAWDCF modemline support 6089 1.1 kardel * 6090 1.1 kardel * Revision 4.41 2000/04/09 19:50:45 kardel 6091 1.1 kardel * fixed rawdcfdtr_init() -> rawdcf_init_1 6092 1.1 kardel * 6093 1.1 kardel * Revision 4.40 2000/04/09 15:27:55 kardel 6094 1.1 kardel * modem line fiddle in rawdcf_init_2 6095 1.1 kardel * 6096 1.1 kardel * Revision 4.39 2000/03/18 09:16:55 kardel 6097 1.1 kardel * PPSAPI integration 6098 1.1 kardel * 6099 1.1 kardel * Revision 4.38 2000/03/05 20:25:06 kardel 6100 1.1 kardel * support PPSAPI 6101 1.1 kardel * 6102 1.1 kardel * Revision 4.37 2000/03/05 20:11:14 kardel 6103 1.1 kardel * 4.0.99g reconcilation 6104 1.1 kardel * 6105 1.1 kardel * Revision 4.36 1999/11/28 17:18:20 kardel 6106 1.1 kardel * disabled burst mode 6107 1.1 kardel * 6108 1.1 kardel * Revision 4.35 1999/11/28 09:14:14 kardel 6109 1.1 kardel * RECON_4_0_98F 6110 1.1 kardel * 6111 1.1 kardel * Revision 4.34 1999/05/14 06:08:05 kardel 6112 1.1 kardel * store current_time in a suitable container (u_long) 6113 1.1 kardel * 6114 1.1 kardel * Revision 4.33 1999/05/13 21:48:38 kardel 6115 1.1 kardel * double the no response timeout interval 6116 1.1 kardel * 6117 1.1 kardel * Revision 4.32 1999/05/13 20:09:13 kardel 6118 1.1 kardel * complain only about missing polls after a full poll interval 6119 1.1 kardel * 6120 1.1 kardel * Revision 4.31 1999/05/13 19:59:32 kardel 6121 1.1 kardel * add clock type 16 for RTS set DTR clr in RAWDCF 6122 1.1 kardel * 6123 1.1 kardel * Revision 4.30 1999/02/28 20:36:43 kardel 6124 1.1 kardel * fixed printf fmt 6125 1.1 kardel * 6126 1.1 kardel * Revision 4.29 1999/02/28 19:58:23 kardel 6127 1.1 kardel * updated copyright information 6128 1.1 kardel * 6129 1.1 kardel * Revision 4.28 1999/02/28 19:01:50 kardel 6130 1.1 kardel * improved debug out on sent Meinberg messages 6131 1.1 kardel * 6132 1.1 kardel * Revision 4.27 1999/02/28 18:05:55 kardel 6133 1.1 kardel * no linux/ppsclock.h stuff 6134 1.1 kardel * 6135 1.1 kardel * Revision 4.26 1999/02/28 15:27:27 kardel 6136 1.1 kardel * wharton clock integration 6137 1.1 kardel * 6138 1.1 kardel * Revision 4.25 1999/02/28 14:04:46 kardel 6139 1.1 kardel * added missing double quotes to UTC information string 6140 1.1 kardel * 6141 1.1 kardel * Revision 4.24 1999/02/28 12:06:50 kardel 6142 1.1 kardel * (parse_control): using gmprettydate instead of prettydate() 6143 1.1 kardel * (mk_utcinfo): new function for formatting GPS derived UTC information 6144 1.1 kardel * (gps16x_message): changed to use mk_utcinfo() 6145 1.1 kardel * (trimbletsip_message): changed to use mk_utcinfo() 6146 1.1 kardel * ignoring position information in unsynchronized mode 6147 1.1 kardel * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 6148 1.1 kardel * 6149 1.1 kardel * Revision 4.23 1999/02/23 19:47:53 kardel 6150 1.1 kardel * fixed #endifs 6151 1.1 kardel * (stream_receive): fixed formats 6152 1.1 kardel * 6153 1.1 kardel * Revision 4.22 1999/02/22 06:21:02 kardel 6154 1.1 kardel * use new autoconfig symbols 6155 1.1 kardel * 6156 1.1 kardel * Revision 4.21 1999/02/21 12:18:13 kardel 6157 1.1 kardel * 4.91f reconcilation 6158 1.1 kardel * 6159 1.1 kardel * Revision 4.20 1999/02/21 10:53:36 kardel 6160 1.1 kardel * initial Linux PPSkit version 6161 1.1 kardel * 6162 1.1 kardel * Revision 4.19 1999/02/07 09:10:45 kardel 6163 1.1 kardel * clarify STREAMS mitigation rules in comment 6164 1.1 kardel * 6165 1.1 kardel * Revision 4.18 1998/12/20 23:45:34 kardel 6166 1.1 kardel * fix types and warnings 6167 1.1 kardel * 6168 1.1 kardel * Revision 4.17 1998/11/15 21:24:51 kardel 6169 1.1 kardel * cannot access mbg_ routines when CLOCK_MEINBERG 6170 1.1 kardel * is not defined 6171 1.1 kardel * 6172 1.1 kardel * Revision 4.16 1998/11/15 20:28:17 kardel 6173 1.1 kardel * Release 4.0.73e13 reconcilation 6174 1.1 kardel * 6175 1.1 kardel * Revision 4.15 1998/08/22 21:56:08 kardel 6176 1.1 kardel * fixed IO handling for non-STREAM IO 6177 1.1 kardel * 6178 1.1 kardel * Revision 4.14 1998/08/16 19:00:48 kardel 6179 1.1 kardel * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 6180 1.1 kardel * made uval a local variable (killed one of the last globals) 6181 1.1 kardel * (sendetx): added logging of messages when in debug mode 6182 1.1 kardel * (trimble_check): added periodic checks to facilitate re-initialization 6183 1.1 kardel * (trimbletsip_init): made use of EOL character if in non-kernel operation 6184 1.1 kardel * (trimbletsip_message): extended message interpretation 6185 1.1 kardel * (getdbl): fixed data conversion 6186 1.1 kardel * 6187 1.1 kardel * Revision 4.13 1998/08/09 22:29:13 kardel 6188 1.1 kardel * Trimble TSIP support 6189 1.1 kardel * 6190 1.1 kardel * Revision 4.12 1998/07/11 10:05:34 kardel 6191 1.1 kardel * Release 4.0.73d reconcilation 6192 1.1 kardel * 6193 1.1 kardel * Revision 4.11 1998/06/14 21:09:42 kardel 6194 1.1 kardel * Sun acc cleanup 6195 1.1 kardel * 6196 1.1 kardel * Revision 4.10 1998/06/13 12:36:45 kardel 6197 1.1 kardel * signed/unsigned, name clashes 6198 1.1 kardel * 6199 1.1 kardel * Revision 4.9 1998/06/12 15:30:00 kardel 6200 1.1 kardel * prototype fixes 6201 1.1 kardel * 6202 1.1 kardel * Revision 4.8 1998/06/12 11:19:42 kardel 6203 1.1 kardel * added direct input processing routine for refclocks in 6204 1.1 kardel * order to avaiod that single character io gobbles up all 6205 1.1 kardel * receive buffers and drops input data. (Problem started 6206 1.1 kardel * with fast machines so a character a buffer was possible 6207 1.1 kardel * one of the few cases where faster machines break existing 6208 1.1 kardel * allocation algorithms) 6209 1.1 kardel * 6210 1.1 kardel * Revision 4.7 1998/06/06 18:35:20 kardel 6211 1.1 kardel * (parse_start): added BURST mode initialisation 6212 1.1 kardel * 6213 1.1 kardel * Revision 4.6 1998/05/27 06:12:46 kardel 6214 1.1 kardel * RAWDCF_BASEDELAY default added 6215 1.1 kardel * old comment removed 6216 1.1 kardel * casts for ioctl() 6217 1.1 kardel * 6218 1.1 kardel * Revision 4.5 1998/05/25 22:05:09 kardel 6219 1.1 kardel * RAWDCF_SETDTR option removed 6220 1.1 kardel * clock type 14 attempts to set DTR for 6221 1.1 kardel * power supply of RAWDCF receivers 6222 1.1 kardel * 6223 1.1 kardel * Revision 4.4 1998/05/24 16:20:47 kardel 6224 1.1 kardel * updated comments referencing Meinberg clocks 6225 1.1 kardel * added RAWDCF clock with DTR set option as type 14 6226 1.1 kardel * 6227 1.1 kardel * Revision 4.3 1998/05/24 10:48:33 kardel 6228 1.1 kardel * calibrated CONRAD RAWDCF default fudge factor 6229 1.1 kardel * 6230 1.1 kardel * Revision 4.2 1998/05/24 09:59:35 kardel 6231 1.1 kardel * corrected version information (ntpq support) 6232 1.1 kardel * 6233 1.1 kardel * Revision 4.1 1998/05/24 09:52:31 kardel 6234 1.1 kardel * use fixed format only (new IO model) 6235 1.1 kardel * output debug to stdout instead of msyslog() 6236 1.1 kardel * don't include >"< in ASCII output in order not to confuse 6237 1.1 kardel * ntpq parsing 6238 1.1 kardel * 6239 1.1 kardel * Revision 4.0 1998/04/10 19:52:11 kardel 6240 1.1 kardel * Start 4.0 release version numbering 6241 1.1 kardel * 6242 1.1 kardel * Revision 1.2 1998/04/10 19:28:04 kardel 6243 1.1 kardel * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 6244 1.1 kardel * derived from 3.105.1.2 from V3 tree 6245 1.1 kardel * 6246 1.1 kardel * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 6247 1.1 kardel * 6248 1.1 kardel */ 6249