ntp_refclock.c (302408) | ntp_refclock.c (54359) |
---|---|
1/* 2 * ntp_refclock - processing support for reference clocks 3 */ 4#ifdef HAVE_CONFIG_H 5# include <config.h> 6#endif 7 | 1/* 2 * ntp_refclock - processing support for reference clocks 3 */ 4#ifdef HAVE_CONFIG_H 5# include <config.h> 6#endif 7 |
8#include <stdio.h> 9#include <sys/types.h> 10#ifdef HAVE_SYS_IOCTL_H 11# include <sys/ioctl.h> 12#endif /* HAVE_SYS_IOCTL_H */ 13 |
|
8#include "ntpd.h" 9#include "ntp_io.h" 10#include "ntp_unixtime.h" | 14#include "ntpd.h" 15#include "ntp_io.h" 16#include "ntp_unixtime.h" |
11#include "ntp_tty.h" | |
12#include "ntp_refclock.h" 13#include "ntp_stdlib.h" | 17#include "ntp_refclock.h" 18#include "ntp_stdlib.h" |
14#include "ntp_assert.h" | |
15 | 19 |
16#include <stdio.h> 17 18#ifdef HAVE_SYS_IOCTL_H 19# include <sys/ioctl.h> 20#endif /* HAVE_SYS_IOCTL_H */ 21 | |
22#ifdef REFCLOCK 23 | 20#ifdef REFCLOCK 21 |
24#ifdef KERNEL_PLL 25#include "ntp_syscall.h" 26#endif /* KERNEL_PLL */ | 22#ifdef TTYCLK 23# ifdef SCO5_CLOCK 24# include <sys/sio.h> 25# else 26# include <sys/clkdefs.h> 27# endif 28#endif /* TTYCLK */ |
27 | 29 |
30#ifdef HAVE_PPSCLOCK_H 31#include <sys/ppsclock.h> 32#endif /* HAVE_PPSCLOCK_H */ 33 |
|
28#ifdef HAVE_PPSAPI | 34#ifdef HAVE_PPSAPI |
29#include "ppsapi_timepps.h" 30#include "refclock_atom.h" | 35#include <sys/timepps.h> |
31#endif /* HAVE_PPSAPI */ 32 33/* 34 * Reference clock support is provided here by maintaining the fiction | 36#endif /* HAVE_PPSAPI */ 37 38/* 39 * Reference clock support is provided here by maintaining the fiction |
35 * that the clock is actually a peer. As no packets are exchanged with 36 * a reference clock, however, we replace the transmit, receive and 37 * packet procedures with separate code to simulate them. Routines | 40 * that the clock is actually a peer. As no packets are exchanged with a 41 * reference clock, however, we replace the transmit, receive and packet 42 * procedures with separate code to simulate them. Routines |
38 * refclock_transmit() and refclock_receive() maintain the peer 39 * variables in a state analogous to an actual peer and pass reference | 43 * refclock_transmit() and refclock_receive() maintain the peer 44 * variables in a state analogous to an actual peer and pass reference |
40 * clock data on through the filters. Routines refclock_peer() and | 45 * clock data on through the filters. Routines refclock_peer() and |
41 * refclock_unpeer() are called to initialize and terminate reference | 46 * refclock_unpeer() are called to initialize and terminate reference |
42 * clock associations. A set of utility routines is included to open 43 * serial devices, process sample data, and to perform various debugging 44 * functions. | 47 * clock associations. A set of utility routines is included to open 48 * serial devices, process sample data, edit input lines to extract 49 * embedded timestamps and to peform various debugging functions. |
45 * 46 * The main interface used by these routines is the refclockproc | 50 * 51 * The main interface used by these routines is the refclockproc |
47 * structure, which contains for most drivers the decimal equivalants 48 * of the year, day, month, hour, second and millisecond/microsecond 49 * decoded from the ASCII timecode. Additional information includes 50 * the receive timestamp, exception report, statistics tallies, etc. 51 * In addition, there may be a driver-specific unit structure used for | 52 * structure, which contains for most drivers the decimal equivalants of 53 * the year, day, month, hour, second and millisecond/microsecond 54 * decoded from the ASCII timecode. Additional information includes the 55 * receive timestamp, exception report, statistics tallies, etc. In 56 * addition, there may be a driver-specific unit structure used for |
52 * local control of the device. 53 * 54 * The support routines are passed a pointer to the peer structure, | 57 * local control of the device. 58 * 59 * The support routines are passed a pointer to the peer structure, |
55 * which is used for all peer-specific processing and contains a 56 * pointer to the refclockproc structure, which in turn contains a 57 * pointer to the unit structure, if used. The peer structure is 58 * identified by an interface address in the dotted quad form 59 * 127.127.t.u, where t is the clock type and u the unit. | 60 * which is used for all peer-specific processing and contains a pointer 61 * to the refclockproc structure, which in turn containes a pointer to 62 * the unit structure, if used. The peer structure is identified by an 63 * interface address in the dotted quad form 127.127.t.u, where t is the 64 * clock type and u the unit. Some legacy drivers derive the 65 * refclockproc structure pointer from the table typeunit[type][unit]. 66 * This interface is strongly discouraged and may be abandoned in 67 * future. 68 * 69 * The routines include support for the 1-pps signal provided by some 70 * radios and connected via a level converted described in the gadget 71 * directory. The signal is captured using a serial port and one of 72 * three STREAMS modules described in the refclock_atom.c file. For the 73 * highest precision, the signal is captured using the carrier-detect 74 * line of a serial port and either the ppsclock or ppsapi streams 75 * module or some devilish ioctl() folks keep slipping in as a patch. Be 76 * advised ALL support for other than the duly standardized ppsapi 77 * interface will eventually be withdrawn. |
60 */ | 78 */ |
79#define MAXUNIT 4 /* max units */ 80 81#if defined(PPS) || defined(HAVE_PPSAPI) 82int fdpps; /* pps file descriptor */ 83#endif /* PPS HAVE_PPSAPI */ 84 |
|
61#define FUDGEFAC .1 /* fudge correction factor */ | 85#define FUDGEFAC .1 /* fudge correction factor */ |
62#define LF 0x0a /* ASCII LF */ | |
63 | 86 |
64int cal_enable; /* enable refclock calibrate */ | 87/* 88 * Type/unit peer index. Used to find the peer structure for control and 89 * debugging. When all clock drivers have been converted to new style, 90 * this dissapears. 91 */ 92static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT]; |
65 66/* 67 * Forward declarations 68 */ | 93 94/* 95 * Forward declarations 96 */ |
69static int refclock_cmpl_fp (const void *, const void *); 70static int refclock_sample (struct refclockproc *); 71static int refclock_ioctl(int, u_int); | 97#ifdef QSORT_USES_VOID_P 98static int refclock_cmpl_fp P((const void *, const void *)); 99#else 100static int refclock_cmpl_fp P((const double *, const double *)); 101#endif /* QSORT_USES_VOID_P */ 102static int refclock_sample P((struct refclockproc *)); |
72 | 103 |
104#ifdef HAVE_PPSAPI 105extern int pps_assert; /* capture edge 1:assert, 0:clear */ 106extern int pps_hardpps; /* PPS kernel 1:on, 0:off */ 107#endif /* HAVE_PPSAPI */ |
|
73 74/* 75 * refclock_report - note the occurance of an event 76 * 77 * This routine presently just remembers the report and logs it, but 78 * does nothing heroic for the trap handler. It tries to be a good 79 * citizen and bothers the system log only if things change. 80 */ 81void 82refclock_report( 83 struct peer *peer, 84 int code 85 ) 86{ 87 struct refclockproc *pp; 88 | 108 109/* 110 * refclock_report - note the occurance of an event 111 * 112 * This routine presently just remembers the report and logs it, but 113 * does nothing heroic for the trap handler. It tries to be a good 114 * citizen and bothers the system log only if things change. 115 */ 116void 117refclock_report( 118 struct peer *peer, 119 int code 120 ) 121{ 122 struct refclockproc *pp; 123 |
89 pp = peer->procptr; 90 if (pp == NULL) | 124 if (!(pp = peer->procptr)) |
91 return; | 125 return; |
92 93 switch (code) { 94 95 case CEVNT_TIMEOUT: 96 pp->noreply++; 97 break; 98 99 case CEVNT_BADREPLY: | 126 if (code == CEVNT_BADREPLY) |
100 pp->badformat++; | 127 pp->badformat++; |
101 break; 102 103 case CEVNT_FAULT: 104 break; 105 106 case CEVNT_BADDATE: 107 case CEVNT_BADTIME: | 128 if (code == CEVNT_BADTIME) |
108 pp->baddata++; | 129 pp->baddata++; |
109 break; 110 111 default: 112 /* ignore others */ 113 break; 114 } 115 if (pp->lastevent < 15) 116 pp->lastevent++; | 130 if (code == CEVNT_TIMEOUT) 131 pp->noreply++; |
117 if (pp->currentstatus != code) { | 132 if (pp->currentstatus != code) { |
118 pp->currentstatus = (u_char)code; 119 report_event(PEVNT_CLOCK, peer, ceventstr(code)); | 133 pp->currentstatus = code; 134 pp->lastevent = code; 135 if (code == CEVNT_FAULT) 136 msyslog(LOG_ERR, 137 "clock %s event '%s' (0x%02x)", 138 refnumtoa(peer->srcadr.sin_addr.s_addr), 139 ceventstr(code), code); 140 else { 141 NLOG(NLOG_CLOCKEVENT) 142 msyslog(LOG_INFO, 143 "clock %s event '%s' (0x%02x)", 144 refnumtoa(peer->srcadr.sin_addr.s_addr), 145 ceventstr(code), code); 146 } |
120 } | 147 } |
148#ifdef DEBUG 149 if (debug) 150 printf("clock %s event '%s' (0x%02x)\n", 151 refnumtoa(peer->srcadr.sin_addr.s_addr), 152 ceventstr(code), code); 153#endif |
|
121} 122 123 124/* 125 * init_refclock - initialize the reference clock drivers 126 * 127 * This routine calls each of the drivers in turn to initialize internal 128 * variables, if necessary. Most drivers have nothing to say at this 129 * point. 130 */ 131void 132init_refclock(void) 133{ | 154} 155 156 157/* 158 * init_refclock - initialize the reference clock drivers 159 * 160 * This routine calls each of the drivers in turn to initialize internal 161 * variables, if necessary. Most drivers have nothing to say at this 162 * point. 163 */ 164void 165init_refclock(void) 166{ |
134 int i; | 167 int i, j; |
135 | 168 |
136 for (i = 0; i < (int)num_refclock_conf; i++) | 169 for (i = 0; i < (int)num_refclock_conf; i++) { |
137 if (refclock_conf[i]->clock_init != noentry) 138 (refclock_conf[i]->clock_init)(); | 170 if (refclock_conf[i]->clock_init != noentry) 171 (refclock_conf[i]->clock_init)(); |
172 for (j = 0; j < MAXUNIT; j++) 173 typeunit[i][j] = 0; 174 } |
|
139} 140 141 142/* 143 * refclock_newpeer - initialize and start a reference clock 144 * 145 * This routine allocates and initializes the interface structure which 146 * supports a reference clock in the form of an ordinary NTP peer. A --- 15 unchanged lines hidden (view full) --- 162 163 /* 164 * Check for valid clock address. If already running, shut it 165 * down first. 166 */ 167 if (!ISREFCLOCKADR(&peer->srcadr)) { 168 msyslog(LOG_ERR, 169 "refclock_newpeer: clock address %s invalid", | 175} 176 177 178/* 179 * refclock_newpeer - initialize and start a reference clock 180 * 181 * This routine allocates and initializes the interface structure which 182 * supports a reference clock in the form of an ordinary NTP peer. A --- 15 unchanged lines hidden (view full) --- 198 199 /* 200 * Check for valid clock address. If already running, shut it 201 * down first. 202 */ 203 if (!ISREFCLOCKADR(&peer->srcadr)) { 204 msyslog(LOG_ERR, 205 "refclock_newpeer: clock address %s invalid", |
170 stoa(&peer->srcadr)); | 206 ntoa(&peer->srcadr)); |
171 return (0); 172 } 173 clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 174 unit = REFCLOCKUNIT(&peer->srcadr); | 207 return (0); 208 } 209 clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 210 unit = REFCLOCKUNIT(&peer->srcadr); |
175 if (clktype >= num_refclock_conf || | 211 if (clktype >= num_refclock_conf || unit >= MAXUNIT || |
176 refclock_conf[clktype]->clock_start == noentry) { 177 msyslog(LOG_ERR, 178 "refclock_newpeer: clock type %d invalid\n", 179 clktype); 180 return (0); 181 } | 212 refclock_conf[clktype]->clock_start == noentry) { 213 msyslog(LOG_ERR, 214 "refclock_newpeer: clock type %d invalid\n", 215 clktype); 216 return (0); 217 } |
218 refclock_unpeer(peer); |
|
182 183 /* 184 * Allocate and initialize interface structure 185 */ | 219 220 /* 221 * Allocate and initialize interface structure 222 */ |
186 pp = emalloc_zero(sizeof(*pp)); | 223 if (!(pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)))) 224 return (0); 225 memset((char *)pp, 0, sizeof(struct refclockproc)); 226 typeunit[clktype][unit] = peer; |
187 peer->procptr = pp; 188 189 /* 190 * Initialize structures 191 */ 192 peer->refclktype = clktype; | 227 peer->procptr = pp; 228 229 /* 230 * Initialize structures 231 */ 232 peer->refclktype = clktype; |
193 peer->refclkunit = (u_char)unit; | 233 peer->refclkunit = unit; |
194 peer->flags |= FLAG_REFCLOCK; | 234 peer->flags |= FLAG_REFCLOCK; |
195 peer->leap = LEAP_NOTINSYNC; | |
196 peer->stratum = STRATUM_REFCLOCK; | 235 peer->stratum = STRATUM_REFCLOCK; |
197 peer->ppoll = peer->maxpoll; | 236 peer->refid = peer->srcadr.sin_addr.s_addr; 237 peer->maxpoll = peer->minpoll; 238 |
198 pp->type = clktype; | 239 pp->type = clktype; |
199 pp->conf = refclock_conf[clktype]; | |
200 pp->timestarted = current_time; | 240 pp->timestarted = current_time; |
201 pp->io.fd = -1; | |
202 203 /* | 241 242 /* |
243 * If the interface has been set to any_interface, set it to the 244 * loopback address if we have one. This is so that peers which 245 * are unreachable are easy to see in the peer display. 246 */ 247 if (peer->dstadr == any_interface && loopback_interface != 0) 248 peer->dstadr = loopback_interface; 249 250 /* |
|
204 * Set peer.pmode based on the hmode. For appearances only. 205 */ 206 switch (peer->hmode) { | 251 * Set peer.pmode based on the hmode. For appearances only. 252 */ 253 switch (peer->hmode) { |
207 case MODE_ACTIVE: | 254 255 case MODE_ACTIVE: |
208 peer->pmode = MODE_PASSIVE; 209 break; 210 | 256 peer->pmode = MODE_PASSIVE; 257 break; 258 |
211 default: | 259 default: |
212 peer->pmode = MODE_SERVER; 213 break; 214 } 215 216 /* 217 * Do driver dependent initialization. The above defaults 218 * can be wiggled, then finish up for consistency. 219 */ 220 if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { | 260 peer->pmode = MODE_SERVER; 261 break; 262 } 263 264 /* 265 * Do driver dependent initialization. The above defaults 266 * can be wiggled, then finish up for consistency. 267 */ 268 if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { |
221 refclock_unpeer(peer); | 269 free(pp); |
222 return (0); 223 } | 270 return (0); 271 } |
224 peer->refid = pp->refid; | 272 peer->hpoll = peer->minpoll; 273 peer->ppoll = peer->maxpoll; 274 if (peer->stratum <= 1) 275 peer->refid = pp->refid; 276 else 277 peer->refid = peer->srcadr.sin_addr.s_addr; |
225 return (1); 226} 227 228 229/* 230 * refclock_unpeer - shut down a clock 231 */ 232void 233refclock_unpeer( 234 struct peer *peer /* peer structure pointer */ 235 ) 236{ 237 u_char clktype; 238 int unit; 239 240 /* 241 * Wiggle the driver to release its resources, then give back 242 * the interface structure. 243 */ | 278 return (1); 279} 280 281 282/* 283 * refclock_unpeer - shut down a clock 284 */ 285void 286refclock_unpeer( 287 struct peer *peer /* peer structure pointer */ 288 ) 289{ 290 u_char clktype; 291 int unit; 292 293 /* 294 * Wiggle the driver to release its resources, then give back 295 * the interface structure. 296 */ |
244 if (NULL == peer->procptr) | 297 if (!peer->procptr) |
245 return; | 298 return; |
246 | |
247 clktype = peer->refclktype; 248 unit = peer->refclkunit; 249 if (refclock_conf[clktype]->clock_shutdown != noentry) 250 (refclock_conf[clktype]->clock_shutdown)(unit, peer); 251 free(peer->procptr); | 299 clktype = peer->refclktype; 300 unit = peer->refclkunit; 301 if (refclock_conf[clktype]->clock_shutdown != noentry) 302 (refclock_conf[clktype]->clock_shutdown)(unit, peer); 303 free(peer->procptr); |
252 peer->procptr = NULL; | 304 peer->procptr = 0; |
253} 254 255 256/* | 305} 306 307 308/* |
257 * refclock_timer - called once per second for housekeeping. 258 */ 259void 260refclock_timer( 261 struct peer *p 262 ) 263{ 264 struct refclockproc * pp; 265 int unit; 266 267 unit = p->refclkunit; 268 pp = p->procptr; 269 if (pp->conf->clock_timer != noentry) 270 (*pp->conf->clock_timer)(unit, p); 271 if (pp->action != NULL && pp->nextaction <= current_time) 272 (*pp->action)(p); 273} 274 275 276/* | |
277 * refclock_transmit - simulate the transmit procedure 278 * 279 * This routine implements the NTP transmit procedure for a reference 280 * clock. This provides a mechanism to call the driver at the NTP poll 281 * interval, as well as provides a reachability mechanism to detect a 282 * broken radio or other madness. 283 */ 284void 285refclock_transmit( 286 struct peer *peer /* peer structure pointer */ 287 ) 288{ 289 u_char clktype; 290 int unit; | 309 * refclock_transmit - simulate the transmit procedure 310 * 311 * This routine implements the NTP transmit procedure for a reference 312 * clock. This provides a mechanism to call the driver at the NTP poll 313 * interval, as well as provides a reachability mechanism to detect a 314 * broken radio or other madness. 315 */ 316void 317refclock_transmit( 318 struct peer *peer /* peer structure pointer */ 319 ) 320{ 321 u_char clktype; 322 int unit; |
323 int hpoll; 324 u_long next; |
|
291 292 clktype = peer->refclktype; 293 unit = peer->refclkunit; 294 peer->sent++; | 325 326 clktype = peer->refclktype; 327 unit = peer->refclkunit; 328 peer->sent++; |
295 get_systime(&peer->xmt); | |
296 297 /* 298 * This is a ripoff of the peer transmit routine, but 299 * specialized for reference clocks. We do a little less 300 * protocol here and call the driver-specific transmit routine. 301 */ | 329 330 /* 331 * This is a ripoff of the peer transmit routine, but 332 * specialized for reference clocks. We do a little less 333 * protocol here and call the driver-specific transmit routine. 334 */ |
335 hpoll = peer->hpoll; 336 next = peer->outdate; |
|
302 if (peer->burst == 0) { 303 u_char oreach; 304#ifdef DEBUG 305 if (debug) 306 printf("refclock_transmit: at %ld %s\n", | 337 if (peer->burst == 0) { 338 u_char oreach; 339#ifdef DEBUG 340 if (debug) 341 printf("refclock_transmit: at %ld %s\n", |
307 current_time, stoa(&(peer->srcadr))); | 342 current_time, ntoa(&(peer->srcadr))); |
308#endif 309 310 /* 311 * Update reachability and poll variables like the 312 * network code. 313 */ | 343#endif 344 345 /* 346 * Update reachability and poll variables like the 347 * network code. 348 */ |
314 oreach = peer->reach & 0xfe; 315 peer->reach <<= 1; 316 if (!(peer->reach & 0x0f)) 317 clock_filter(peer, 0., 0., MAXDISPERSE); 318 peer->outdate = current_time; 319 if (!peer->reach) { 320 if (oreach) { 321 report_event(PEVNT_UNREACH, peer, NULL); | 349 oreach = peer->reach; 350 if (oreach & 0x01) 351 peer->valid++; 352 if (oreach & 0x80) 353 peer->valid--; 354 peer->reach <<= 1; 355 if (peer->reach == 0) { 356 if (oreach != 0) { 357 report_event(EVNT_UNREACH, peer); |
322 peer->timereachable = current_time; | 358 peer->timereachable = current_time; |
359 peer_clear(peer); |
|
323 } 324 } else { | 360 } 361 } else { |
362 if ((oreach & 0x03) == 0) { 363 clock_filter(peer, 0., 0., MAXDISPERSE); 364 clock_select(); 365 } 366 if (peer->valid <= 2) { 367 hpoll--; 368 } else if (peer->valid > NTP_SHIFT - 2) 369 hpoll++; |
|
325 if (peer->flags & FLAG_BURST) 326 peer->burst = NSTAGE; 327 } | 370 if (peer->flags & FLAG_BURST) 371 peer->burst = NSTAGE; 372 } |
328 } else { 329 peer->burst--; | 373 next = current_time; |
330 } | 374 } |
375 get_systime(&peer->xmt); |
|
331 if (refclock_conf[clktype]->clock_poll != noentry) 332 (refclock_conf[clktype]->clock_poll)(unit, peer); | 376 if (refclock_conf[clktype]->clock_poll != noentry) 377 (refclock_conf[clktype]->clock_poll)(unit, peer); |
333 poll_update(peer, peer->hpoll); | 378 peer->outdate = next; 379 poll_update(peer, hpoll); 380 if (peer->burst > 0) 381 peer->burst--; 382 poll_update(peer, hpoll); |
334} 335 336 337/* 338 * Compare two doubles - used with qsort() 339 */ | 383} 384 385 386/* 387 * Compare two doubles - used with qsort() 388 */ |
389#ifdef QSORT_USES_VOID_P |
|
340static int 341refclock_cmpl_fp( 342 const void *p1, 343 const void *p2 344 ) 345{ 346 const double *dp1 = (const double *)p1; 347 const double *dp2 = (const double *)p2; 348 349 if (*dp1 < *dp2) | 390static int 391refclock_cmpl_fp( 392 const void *p1, 393 const void *p2 394 ) 395{ 396 const double *dp1 = (const double *)p1; 397 const double *dp2 = (const double *)p2; 398 399 if (*dp1 < *dp2) |
350 return -1; | 400 return (-1); |
351 if (*dp1 > *dp2) | 401 if (*dp1 > *dp2) |
352 return 1; 353 return 0; | 402 return (1); 403 return (0); |
354} | 404} |
405#else 406static int 407refclock_cmpl_fp( 408 const double *dp1, 409 const double *dp2 410 ) 411{ 412 if (*dp1 < *dp2) 413 return (-1); 414 if (*dp1 > *dp2) 415 return (1); 416 return (0); 417} 418#endif /* QSORT_USES_VOID_P */ |
|
355 356 357/* 358 * refclock_process_offset - update median filter 359 * | 419 420 421/* 422 * refclock_process_offset - update median filter 423 * |
360 * This routine uses the given offset and timestamps to construct a new 361 * entry in the median filter circular buffer. Samples that overflow the 362 * filter are quietly discarded. | 424 * This routine uses the given offset and timestamps to construct a new entry in the median filter circular buffer. Samples that overflow the filter are quietly discarded. |
363 */ 364void 365refclock_process_offset( | 425 */ 426void 427refclock_process_offset( |
366 struct refclockproc *pp, /* refclock structure pointer */ 367 l_fp lasttim, /* last timecode timestamp */ 368 l_fp lastrec, /* last receive timestamp */ | 428 struct refclockproc *pp, 429 l_fp offset, 430 l_fp lastrec, |
369 double fudge 370 ) 371{ | 431 double fudge 432 ) 433{ |
372 l_fp lftemp; | |
373 double doffset; 374 | 434 double doffset; 435 |
436 pp->lastref = offset; |
|
375 pp->lastrec = lastrec; | 437 pp->lastrec = lastrec; |
376 lftemp = lasttim; 377 L_SUB(&lftemp, &lastrec); 378 LFPTOD(&lftemp, doffset); | 438 pp->variance = 0; 439 L_SUB(&offset, &lastrec); 440 LFPTOD(&offset, doffset); |
379 SAMPLE(doffset + fudge); 380} 381 | 441 SAMPLE(doffset + fudge); 442} 443 |
382 | |
383/* 384 * refclock_process - process a sample from the clock | 444/* 445 * refclock_process - process a sample from the clock |
385 * refclock_process_f - refclock_process with other than time1 fudge | |
386 * 387 * This routine converts the timecode in the form days, hours, minutes, 388 * seconds and milliseconds/microseconds to internal timestamp format, 389 * then constructs a new entry in the median filter circular buffer. 390 * Return success (1) if the data are correct and consistent with the 391 * converntional calendar. | 446 * 447 * This routine converts the timecode in the form days, hours, minutes, 448 * seconds and milliseconds/microseconds to internal timestamp format, 449 * then constructs a new entry in the median filter circular buffer. 450 * Return success (1) if the data are correct and consistent with the 451 * converntional calendar. |
392 * 393 * Important for PPS users: Normally, the pp->lastrec is set to the 394 * system time when the on-time character is received and the pp->year, 395 * ..., pp->second decoded and the seconds fraction pp->nsec in 396 * nanoseconds). When a PPS offset is available, pp->nsec is forced to 397 * zero and the fraction for pp->lastrec is set to the PPS offset. 398 */ | 452*/ |
399int | 453int |
400refclock_process_f( 401 struct refclockproc *pp, /* refclock structure pointer */ 402 double fudge | 454refclock_process( 455 struct refclockproc *pp |
403 ) 404{ | 456 ) 457{ |
405 l_fp offset, ltemp; | 458 l_fp offset; |
406 407 /* 408 * Compute the timecode timestamp from the days, hours, minutes, 409 * seconds and milliseconds/microseconds of the timecode. Use 410 * clocktime() for the aggregate seconds and the msec/usec for 411 * the fraction, when present. Note that this code relies on the 412 * filesystem time for the years and does not use the years of 413 * the timecode. 414 */ 415 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 416 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 417 return (0); | 459 460 /* 461 * Compute the timecode timestamp from the days, hours, minutes, 462 * seconds and milliseconds/microseconds of the timecode. Use 463 * clocktime() for the aggregate seconds and the msec/usec for 464 * the fraction, when present. Note that this code relies on the 465 * filesystem time for the years and does not use the years of 466 * the timecode. 467 */ 468 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 469 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 470 return (0); |
418 419 offset.l_uf = 0; 420 DTOLFP(pp->nsec / 1e9, <emp); 421 L_ADD(&offset, <emp); 422 refclock_process_offset(pp, offset, pp->lastrec, fudge); | 471 if (pp->usec) { 472 TVUTOTSF(pp->usec, offset.l_uf); 473 } else { 474 MSUTOTSF(pp->msec, offset.l_uf); 475 } 476 refclock_process_offset(pp, offset, pp->lastrec, 477 pp->fudgetime1); |
423 return (1); 424} 425 | 478 return (1); 479} 480 |
426 427int 428refclock_process( 429 struct refclockproc *pp /* refclock structure pointer */ 430) 431{ 432 return refclock_process_f(pp, pp->fudgetime1); 433} 434 435 | |
436/* 437 * refclock_sample - process a pile of samples from the clock 438 * 439 * This routine implements a recursive median filter to suppress spikes 440 * in the data, as well as determine a performance statistic. It | 481/* 482 * refclock_sample - process a pile of samples from the clock 483 * 484 * This routine implements a recursive median filter to suppress spikes 485 * in the data, as well as determine a performance statistic. It |
441 * calculates the mean offset and RMS jitter. A time adjustment 442 * fudgetime1 can be added to the final offset to compensate for various 443 * systematic errors. The routine returns the number of samples 444 * processed, which could be zero. | 486 * calculates the mean offset and mean-square variance. A time 487 * adjustment fudgetime1 can be added to the final offset to compensate 488 * for various systematic errors. The routine returns the number of 489 * samples processed, which could be 0. |
445 */ 446static int 447refclock_sample( | 490 */ 491static int 492refclock_sample( |
448 struct refclockproc *pp /* refclock structure pointer */ | 493 struct refclockproc *pp |
449 ) 450{ | 494 ) 495{ |
451 size_t i, j, k, m, n; 452 double off[MAXSTAGE]; 453 double offset; | 496 int i, j, k, n; 497 double offset, disp; 498 double off[MAXSTAGE]; |
454 455 /* 456 * Copy the raw offsets and sort into ascending order. Don't do 457 * anything if the buffer is empty. 458 */ | 499 500 /* 501 * Copy the raw offsets and sort into ascending order. Don't do 502 * anything if the buffer is empty. 503 */ |
459 n = 0; 460 while (pp->codeproc != pp->coderecv) { 461 pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 462 off[n] = pp->filter[pp->codeproc]; 463 n++; 464 } 465 if (n == 0) | 504 if (pp->codeproc == pp->coderecv) |
466 return (0); | 505 return (0); |
467 | 506 n = 0; 507 while (pp->codeproc != pp->coderecv) 508 off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE]; |
468 if (n > 1) | 509 if (n > 1) |
469 qsort(off, n, sizeof(off[0]), refclock_cmpl_fp); | 510 qsort((char *)off, n, sizeof(double), refclock_cmpl_fp); |
470 471 /* 472 * Reject the furthest from the median of the samples until 473 * approximately 60 percent of the samples remain. 474 */ 475 i = 0; j = n; | 511 512 /* 513 * Reject the furthest from the median of the samples until 514 * approximately 60 percent of the samples remain. 515 */ 516 i = 0; j = n; |
476 m = n - (n * 4) / 10; 477 while ((j - i) > m) { | 517 k = n - (n * 2) / NSTAGE; 518 while ((j - i) > k) { |
478 offset = off[(j + i) / 2]; 479 if (off[j - 1] - offset < offset - off[i]) 480 i++; /* reject low end */ 481 else 482 j--; /* reject high end */ 483 } 484 485 /* | 519 offset = off[(j + i) / 2]; 520 if (off[j - 1] - offset < offset - off[i]) 521 i++; /* reject low end */ 522 else 523 j--; /* reject high end */ 524 } 525 526 /* |
486 * Determine the offset and jitter. | 527 * Determine the offset and variance. |
487 */ | 528 */ |
488 pp->offset = 0; 489 pp->jitter = 0; 490 for (k = i; k < j; k++) { 491 pp->offset += off[k]; 492 if (k > i) 493 pp->jitter += SQUARE(off[k] - off[k - 1]); | 529 offset = disp = 0; 530 for (; i < j; i++) { 531 offset += off[i]; 532 disp += SQUARE(off[i]); |
494 } | 533 } |
495 pp->offset /= m; 496 pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision)); | 534 offset /= k; 535 pp->offset = offset; 536 pp->variance += disp / k - SQUARE(offset); |
497#ifdef DEBUG 498 if (debug) 499 printf( | 537#ifdef DEBUG 538 if (debug) 539 printf( |
500 "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", 501 (int)n, pp->offset, pp->disp, pp->jitter); | 540 "refclock_sample: n %d offset %.6f disp %.6f std %.6f\n", 541 n, pp->offset, pp->disp, SQRT(pp->variance)); |
502#endif | 542#endif |
503 return (int)n; | 543 return (n); |
504} 505 506 507/* 508 * refclock_receive - simulate the receive and packet procedures 509 * 510 * This routine simulates the NTP receive and packet procedures for a 511 * reference clock. This provides a mechanism in which the ordinary NTP --- 6 unchanged lines hidden (view full) --- 518 struct peer *peer /* peer structure pointer */ 519 ) 520{ 521 struct refclockproc *pp; 522 523#ifdef DEBUG 524 if (debug) 525 printf("refclock_receive: at %lu %s\n", | 544} 545 546 547/* 548 * refclock_receive - simulate the receive and packet procedures 549 * 550 * This routine simulates the NTP receive and packet procedures for a 551 * reference clock. This provides a mechanism in which the ordinary NTP --- 6 unchanged lines hidden (view full) --- 558 struct peer *peer /* peer structure pointer */ 559 ) 560{ 561 struct refclockproc *pp; 562 563#ifdef DEBUG 564 if (debug) 565 printf("refclock_receive: at %lu %s\n", |
526 current_time, stoa(&peer->srcadr)); | 566 current_time, ntoa(&peer->srcadr)); |
527#endif 528 529 /* 530 * Do a little sanity dance and update the peer structure. Groom 531 * the median filter samples and give the data to the clock 532 * filter. 533 */ | 567#endif 568 569 /* 570 * Do a little sanity dance and update the peer structure. Groom 571 * the median filter samples and give the data to the clock 572 * filter. 573 */ |
574 peer->received++; |
|
534 pp = peer->procptr; | 575 pp = peer->procptr; |
576 peer->processed++; 577 peer->timereceived = current_time; |
|
535 peer->leap = pp->leap; | 578 peer->leap = pp->leap; |
536 if (peer->leap == LEAP_NOTINSYNC) | 579 if (peer->leap == LEAP_NOTINSYNC) { 580 refclock_report(peer, CEVNT_FAULT); |
537 return; | 581 return; |
538 539 peer->received++; 540 peer->timereceived = current_time; 541 if (!peer->reach) { 542 report_event(PEVNT_REACH, peer, NULL); 543 peer->timereachable = current_time; | |
544 } | 582 } |
583 if (peer->reach == 0) 584 report_event(EVNT_REACH, peer); |
|
545 peer->reach |= 1; | 585 peer->reach |= 1; |
546 peer->reftime = pp->lastref; 547 peer->aorg = pp->lastrec; 548 peer->rootdisp = pp->disp; 549 get_systime(&peer->dst); | 586 peer->reftime = peer->org = pp->lastrec; 587 peer->rootdispersion = pp->disp + SQRT(pp->variance); 588 get_systime(&peer->rec); |
550 if (!refclock_sample(pp)) 551 return; | 589 if (!refclock_sample(pp)) 590 return; |
552 553 clock_filter(peer, pp->offset, 0., pp->jitter); 554 if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer != 555 NULL) { 556 if (sys_peer->refclktype == REFCLK_ATOM_PPS && 557 peer->refclktype != REFCLK_ATOM_PPS) 558 pp->fudgetime1 -= pp->offset * FUDGEFAC; 559 } | 591 clock_filter(peer, pp->offset, 0., 0.); 592 clock_select(); 593 record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), 594 peer->offset, peer->delay, CLOCK_PHI * (current_time - 595 peer->epoch), SQRT(peer->variance)); 596 if (pps_control && pp->sloppyclockflag & CLK_FLAG1) 597 pp->fudgetime1 -= pp->offset * FUDGEFAC; |
560} 561 | 598} 599 |
562 | |
563/* 564 * refclock_gtlin - groom next input line and extract timestamp 565 * 566 * This routine processes the timecode received from the clock and | 600/* 601 * refclock_gtlin - groom next input line and extract timestamp 602 * 603 * This routine processes the timecode received from the clock and |
567 * strips the parity bit and control characters. It returns the number 568 * of characters in the line followed by a NULL character ('\0'), which 569 * is not included in the count. In case of an empty line, the previous 570 * line is preserved. | 604 * removes the parity bit and control characters. If a timestamp is 605 * present in the timecode, as produced by the tty_clk STREAMS module, 606 * it returns that as the timestamp; otherwise, it returns the buffer 607 * timestamp. The routine return code is the number of characters in 608 * the line. |
571 */ 572int 573refclock_gtlin( 574 struct recvbuf *rbufp, /* receive buffer pointer */ | 609 */ 610int 611refclock_gtlin( 612 struct recvbuf *rbufp, /* receive buffer pointer */ |
575 char *lineptr, /* current line pointer */ 576 int bmax, /* remaining characters in line */ 577 l_fp *tsptr /* pointer to timestamp returned */ | 613 char *lineptr, /* current line pointer */ 614 int bmax, /* remaining characters in line */ 615 l_fp *tsptr /* pointer to timestamp returned */ |
578 ) 579{ | 616 ) 617{ |
580 const char *sp, *spend; 581 char *dp, *dpend; 582 int dlen; | 618 char *dpt, *dpend, *dp; 619 int i; 620 l_fp trtmp, tstmp; 621 char c; 622#ifdef TIOCDCDTIMESTAMP 623 struct timeval dcd_time; 624#endif /* TIOCDCDTIMESTAMP */ 625#ifdef HAVE_PPSAPI 626 pps_info_t pi; 627 struct timespec timeout, *tsp; 628 double a; 629#endif /* HAVE_PPSAPI */ |
583 | 630 |
584 if (bmax <= 0) 585 return (0); 586 587 dp = lineptr; 588 dpend = dp + bmax - 1; /* leave room for NUL pad */ 589 sp = (const char *)rbufp->recv_buffer; 590 spend = sp + rbufp->recv_length; 591 592 while (sp != spend && dp != dpend) { 593 char c; 594 595 c = *sp++ & 0x7f; 596 if (c >= 0x20 && c < 0x7f) 597 *dp++ = c; 598 } 599 /* Get length of data written to the destination buffer. If 600 * zero, do *not* place a NUL byte to preserve the previous 601 * buffer content. | 631 /* 632 * Check for the presence of a timestamp left by the tty_clock 633 * module and, if present, use that instead of the buffer 634 * timestamp captured by the I/O routines. We recognize a 635 * timestamp by noting its value is earlier than the buffer 636 * timestamp, but not more than one second earlier. |
602 */ | 637 */ |
603 dlen = dp - lineptr; 604 if (dlen) 605 *dp = '\0'; 606 *tsptr = rbufp->recv_time; 607 DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n", 608 rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen, 609 (dlen != 0) 610 ? lineptr 611 : "")); 612 return (dlen); 613} | 638 dpt = (char *)&rbufp->recv_space; 639 dpend = dpt + rbufp->recv_length; 640 trtmp = rbufp->recv_time; |
614 | 641 |
615 616/* 617 * refclock_gtraw - get next line/chunk of data 618 * 619 * This routine returns the raw data received from the clock in both 620 * canonical or raw modes. The terminal interface routines map CR to LF. 621 * In canonical mode this results in two lines, one containing data 622 * followed by LF and another containing only LF. In raw mode the 623 * interface routines can deliver arbitraty chunks of data from one 624 * character to a maximum specified by the calling routine. In either 625 * mode the routine returns the number of characters in the line 626 * followed by a NULL character ('\0'), which is not included in the 627 * count. 628 * 629 * *tsptr receives a copy of the buffer timestamp. 630 */ 631int 632refclock_gtraw( 633 struct recvbuf *rbufp, /* receive buffer pointer */ 634 char *lineptr, /* current line pointer */ 635 int bmax, /* remaining characters in line */ 636 l_fp *tsptr /* pointer to timestamp returned */ 637 ) 638{ 639 if (bmax <= 0) 640 return (0); 641 bmax -= 1; /* leave room for trailing NUL */ 642 if (bmax > rbufp->recv_length) 643 bmax = rbufp->recv_length; 644 memcpy(lineptr, rbufp->recv_buffer, bmax); 645 lineptr[bmax] = '\0'; 646 647 *tsptr = rbufp->recv_time; 648 DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n", 649 rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax, 650 lineptr)); 651 return (bmax); 652} 653 654 655/* 656 * indicate_refclock_packet() 657 * 658 * Passes a fragment of refclock input read from the device to the 659 * driver direct input routine, which may consume it (batch it for 660 * queuing once a logical unit is assembled). If it is not so 661 * consumed, queue it for the driver's receive entrypoint. 662 * 663 * The return value is TRUE if the data has been consumed as a fragment 664 * and should not be counted as a received packet. 665 */ 666int 667indicate_refclock_packet( 668 struct refclockio * rio, 669 struct recvbuf * rb 670 ) 671{ 672 /* Does this refclock use direct input routine? */ 673 if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) { 674 /* 675 * data was consumed - nothing to pass up 676 * into block input machine 677 */ 678 freerecvbuf(rb); 679 680 return TRUE; | 642#ifdef HAVE_PPSAPI 643 timeout.tv_sec = 0; 644 timeout.tv_nsec = 0; 645 if ((rbufp->fd == fdpps) && 646 (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &pi, &timeout) >= 0)) { 647 if(pps_assert) 648 tsp = &pi.assert_timestamp; 649 else 650 tsp = &pi.clear_timestamp; 651 a = tsp->tv_nsec; 652 a /= 1e9; 653 tstmp.l_uf = a * 4294967296.0; 654 tstmp.l_ui = tsp->tv_sec; 655 tstmp.l_ui += JAN_1970; 656 L_SUB(&trtmp, &tstmp); 657 if (trtmp.l_ui == 0) { 658#ifdef DEBUG 659 if (debug > 1) { 660 printf( 661 "refclock_gtlin: fd %d time_pps_fetch %s", 662 fdpps, lfptoa(&tstmp, 6)); 663 printf(" sigio %s\n", lfptoa(&trtmp, 6)); 664 } 665#endif 666 trtmp = tstmp; 667 goto gotit; 668 } else 669 trtmp = rbufp->recv_time; |
681 } | 670 } |
682 add_full_recv_buffer(rb); | 671#endif /* HAVE_PPSAPI */ 672#ifdef TIOCDCDTIMESTAMP 673 if(ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) { 674 TVTOTS(&dcd_time, &tstmp); 675 tstmp.l_ui += JAN_1970; 676 L_SUB(&trtmp, &tstmp); 677 if (trtmp.l_ui == 0) { 678#ifdef DEBUG 679 if (debug > 1) { 680 printf( 681 "refclock_gtlin: fd %d DCDTIMESTAMP %s", 682 rbufp->fd, lfptoa(&tstmp, 6)); 683 printf(" sigio %s\n", lfptoa(&trtmp, 6)); 684 } 685#endif 686 trtmp = tstmp; 687 goto gotit; 688 } else 689 trtmp = rbufp->recv_time; 690 } 691 else 692 /* XXX fallback to old method if kernel refuses TIOCDCDTIMESTAMP */ 693#endif /* TIOCDCDTIMESTAMP */ 694 if (dpend >= dpt + 8) { 695 if (buftvtots(dpend - 8, &tstmp)) { 696 L_SUB(&trtmp, &tstmp); 697 if (trtmp.l_ui == 0) { 698#ifdef DEBUG 699 if (debug > 1) { 700 printf( 701 "refclock_gtlin: fd %d ldisc %s", 702 rbufp->fd, lfptoa(&trtmp, 6)); 703 get_systime(&trtmp); 704 L_SUB(&trtmp, &tstmp); 705 printf(" sigio %s\n", lfptoa(&trtmp, 6)); 706 } 707#endif 708 dpend -= 8; 709 trtmp = tstmp; 710 } else 711 trtmp = rbufp->recv_time; 712 } 713 } |
683 | 714 |
684 return FALSE; 685} 686 687 688/* 689 * process_refclock_packet() 690 * 691 * Used for deferred processing of 'io_input' on systems where threading 692 * is used (notably Windows). This is acting as a trampoline to make the 693 * real calls to the refclock functions. 694 */ 695#ifdef HAVE_IO_COMPLETION_PORT 696void 697process_refclock_packet( 698 struct recvbuf * rb 699 ) 700{ 701 struct refclockio * rio; 702 703 /* get the refclockio structure from the receive buffer */ 704 rio = &rb->recv_peer->procptr->io; 705 706 /* call 'clock_recv' if either there is no input function or the 707 * raw input function tells us to feed the packet to the 708 * receiver. | 715#if defined(HAVE_PPSAPI) || defined(TIOCDCDTIMESTAMP) 716gotit: 717#endif 718 /* 719 * Edit timecode to remove control chars. Don't monkey with the 720 * line buffer if the input buffer contains no ASCII printing 721 * characters. |
709 */ | 722 */ |
710 if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) { 711 rio->recvcount++; 712 packets_received++; 713 handler_pkts++; 714 (*rio->clock_recv)(rb); | 723 if (dpend - dpt > bmax - 1) 724 dpend = dpt + bmax - 1; 725 for (dp = lineptr; dpt < dpend; dpt++) { 726 c = *dpt & 0x7f; 727 if (c >= ' ') 728 *dp++ = c; |
715 } | 729 } |
730 i = dp - lineptr; 731 if (i > 0) 732 *dp = '\0'; 733#ifdef DEBUG 734 if (debug > 1 && i > 0) 735 printf("refclock_gtlin: fd %d time %s timecode %d %s\n", 736 rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); 737#endif 738 *tsptr = trtmp; 739 return (i); |
|
716} | 740} |
717#endif /* HAVE_IO_COMPLETION_PORT */ | |
718 | 741 |
719 | |
720/* 721 * The following code does not apply to WINNT & VMS ... 722 */ | 742/* 743 * The following code does not apply to WINNT & VMS ... 744 */ |
723#if !defined(SYS_VXWORKS) && !defined(SYS_WINNT) | 745#if !defined SYS_VXWORKS && !defined SYS_WINNT |
724#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 725 726/* 727 * refclock_open - open serial port for reference clock 728 * 729 * This routine opens a serial port for I/O and sets default options. It | 746#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 747 748/* 749 * refclock_open - open serial port for reference clock 750 * 751 * This routine opens a serial port for I/O and sets default options. It |
730 * returns the file descriptor if successful, or logs an error and 731 * returns -1. | 752 * returns the file descriptor if success and zero if failure. |
732 */ 733int 734refclock_open( | 753 */ 754int 755refclock_open( |
735 const char *dev, /* device name pointer */ 736 u_int speed, /* serial port speed (code) */ 737 u_int lflags /* line discipline flags */ | 756 char *dev, /* device name pointer */ 757 int speed, /* serial port speed (code) */ 758 int flags /* line discipline flags */ |
738 ) 739{ | 759 ) 760{ |
740 int fd; 741 int omode; 742#ifdef O_NONBLOCK 743 char trash[128]; /* litter bin for old input data */ 744#endif | 761 int fd, i; 762#ifdef HAVE_TERMIOS 763 struct termios ttyb, *ttyp; 764#endif /* HAVE_TERMIOS */ 765#ifdef HAVE_SYSV_TTYS 766 struct termio ttyb, *ttyp; 767#endif /* HAVE_SYSV_TTYS */ 768#ifdef HAVE_BSD_TTYS 769 struct sgttyb ttyb, *ttyp; 770#endif /* HAVE_BSD_TTYS */ 771#ifdef TIOCMGET 772 u_long ltemp; 773#endif /* TIOCMGET */ |
745 746 /* 747 * Open serial port and set default options 748 */ | 774 775 /* 776 * Open serial port and set default options 777 */ |
749 omode = O_RDWR; | |
750#ifdef O_NONBLOCK | 778#ifdef O_NONBLOCK |
751 omode |= O_NONBLOCK; 752#endif 753#ifdef O_NOCTTY 754 omode |= O_NOCTTY; 755#endif 756 757 fd = open(dev, omode, 0777); 758 /* refclock_open() long returned 0 on failure, avoid it. */ 759 if (0 == fd) { 760 fd = dup(0); 761 SAVE_ERRNO( 762 close(0); 763 ) | 779 fd = open(dev, O_RDWR | O_NONBLOCK, 0777); 780#else 781 fd = open(dev, O_RDWR, 0777); 782#endif /* O_NONBLOCK */ 783 if (fd == -1) { 784 msyslog(LOG_ERR, "refclock_open: %s: %m", dev); 785 return (0); |
764 } | 786 } |
765 if (fd < 0) { 766 SAVE_ERRNO( 767 msyslog(LOG_ERR, "refclock_open %s: %m", dev); 768 ) 769 return -1; 770 } 771 if (!refclock_setup(fd, speed, lflags)) { 772 close(fd); 773 return -1; 774 } 775 if (!refclock_ioctl(fd, lflags)) { 776 close(fd); 777 return -1; 778 } 779#ifdef O_NONBLOCK 780 /* 781 * We want to make sure there is no pending trash in the input 782 * buffer. Since we have non-blocking IO available, this is a 783 * good moment to read and dump all available outdated stuff 784 * that might have become toxic for the driver. 785 */ 786 while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR) 787 /*NOP*/; 788#endif 789 return fd; 790} | |
791 | 787 |
792 793/* 794 * refclock_setup - initialize terminal interface structure 795 */ 796int 797refclock_setup( 798 int fd, /* file descriptor */ 799 u_int speed, /* serial port speed (code) */ 800 u_int lflags /* line discipline flags */ 801 ) 802{ 803 int i; 804 TTY ttyb, *ttyp; 805 | |
806 /* | 788 /* |
807 * By default, the serial line port is initialized in canonical 808 * (line-oriented) mode at specified line speed, 8 bits and no 809 * parity. LF ends the line and CR is mapped to LF. The break, 810 * erase and kill functions are disabled. There is a different 811 * section for each terminal interface, as selected at compile 812 * time. The flag bits can be used to set raw mode and echo. | 789 * The following sections initialize the serial line port in 790 * canonical (line-oriented) mode and set the specified line 791 * speed, 8 bits and no parity. The modem control, break, erase 792 * and kill functions are normally disabled. There is a 793 * different section for each terminal interface, as selected at 794 * compile time. |
813 */ 814 ttyp = &ttyb; | 795 */ 796 ttyp = &ttyb; |
815#ifdef HAVE_TERMIOS | |
816 | 797 |
798#ifdef HAVE_TERMIOS |
|
817 /* 818 * POSIX serial line parameters (termios interface) 819 */ 820 if (tcgetattr(fd, ttyp) < 0) { | 799 /* 800 * POSIX serial line parameters (termios interface) 801 */ 802 if (tcgetattr(fd, ttyp) < 0) { |
821 SAVE_ERRNO( 822 msyslog(LOG_ERR, 823 "refclock_setup fd %d tcgetattr: %m", 824 fd); 825 ) 826 return FALSE; | 803 msyslog(LOG_ERR, 804 "refclock_open: fd %d tcgetattr: %m", fd); 805 return (0); |
827 } 828 829 /* 830 * Set canonical mode and local connection; set specified speed, 831 * 8 bits and no parity; map CR to NL; ignore break. 832 */ | 806 } 807 808 /* 809 * Set canonical mode and local connection; set specified speed, 810 * 8 bits and no parity; map CR to NL; ignore break. 811 */ |
833 if (speed) { 834 u_int ltemp = 0; 835 836 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 837 ttyp->c_oflag = 0; 838 ttyp->c_cflag = CS8 | CLOCAL | CREAD; 839 if (lflags & LDISC_7O1) { 840 /* HP Z3801A needs 7-bit, odd parity */ 841 ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; 842 } 843 cfsetispeed(&ttyb, speed); 844 cfsetospeed(&ttyb, speed); 845 for (i = 0; i < NCCS; ++i) 846 ttyp->c_cc[i] = '\0'; 847 848#if defined(TIOCMGET) && !defined(SCO5_CLOCK) 849 850 /* 851 * If we have modem control, check to see if modem leads 852 * are active; if so, set remote connection. This is 853 * necessary for the kernel pps mods to work. 854 */ 855 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 856 msyslog(LOG_ERR, 857 "refclock_setup fd %d TIOCMGET: %m", fd); 858#ifdef DEBUG 859 if (debug) 860 printf("refclock_setup fd %d modem status: 0x%x\n", 861 fd, ltemp); 862#endif 863 if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) 864 ttyp->c_cflag &= ~CLOCAL; 865#endif /* TIOCMGET */ | 812 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 813 ttyp->c_oflag = 0; 814 ttyp->c_cflag = CS8 | CLOCAL | CREAD; 815 (void)cfsetispeed(&ttyb, (u_int)speed); 816 (void)cfsetospeed(&ttyb, (u_int)speed); 817 ttyp->c_lflag = ICANON; 818 for (i = 0; i < NCCS; ++i) 819 { 820 ttyp->c_cc[i] = '\0'; |
866 } 867 868 /* | 821 } 822 823 /* |
869 * Set raw and echo modes. These can be changed on-fly. | 824 * Some special cases |
870 */ | 825 */ |
871 ttyp->c_lflag = ICANON; 872 if (lflags & LDISC_RAW) { 873 ttyp->c_lflag = 0; | 826 if (flags & LDISC_RAW) { |
874 ttyp->c_iflag = 0; | 827 ttyp->c_iflag = 0; |
828 ttyp->c_lflag = 0; |
|
875 ttyp->c_cc[VMIN] = 1; 876 } | 829 ttyp->c_cc[VMIN] = 1; 830 } |
877 if (lflags & LDISC_ECHO) 878 ttyp->c_lflag |= ECHO; 879 if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 880 SAVE_ERRNO( 881 msyslog(LOG_ERR, 882 "refclock_setup fd %d TCSANOW: %m", 883 fd); 884 ) 885 return FALSE; 886 } 887 | 831#if defined(TIOCMGET) && !defined(SCO5_CLOCK) |
888 /* | 832 /* |
889 * flush input and output buffers to discard any outdated stuff 890 * that might have become toxic for the driver. Failing to do so 891 * is logged, but we keep our fingers crossed otherwise. | 833 * If we have modem control, check to see if modem leads are 834 * active; if so, set remote connection. This is necessary for 835 * the kernel pps mods to work. |
892 */ | 836 */ |
893 if (tcflush(fd, TCIOFLUSH) < 0) 894 msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m", 895 fd); | 837 ltemp = 0; 838 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 839 msyslog(LOG_ERR, 840 "refclock_open: fd %d TIOCMGET failed: %m", fd); 841#ifdef DEBUG 842 if (debug) 843 printf("refclock_open: fd %d modem status 0x%lx\n", 844 fd, ltemp); 845#endif 846 if (ltemp & TIOCM_DSR) 847 ttyp->c_cflag &= ~CLOCAL; 848#endif /* TIOCMGET */ 849 if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 850 msyslog(LOG_ERR, 851 "refclock_open: fd %d TCSANOW failed: %m", fd); 852 return (0); 853 } 854 if (tcflush(fd, TCIOFLUSH) < 0) { 855 msyslog(LOG_ERR, 856 "refclock_open: fd %d TCIOFLUSH failed: %m", fd); 857 return (0); 858 } |
896#endif /* HAVE_TERMIOS */ 897 898#ifdef HAVE_SYSV_TTYS 899 900 /* 901 * System V serial line parameters (termio interface) 902 * 903 */ 904 if (ioctl(fd, TCGETA, ttyp) < 0) { | 859#endif /* HAVE_TERMIOS */ 860 861#ifdef HAVE_SYSV_TTYS 862 863 /* 864 * System V serial line parameters (termio interface) 865 * 866 */ 867 if (ioctl(fd, TCGETA, ttyp) < 0) { |
905 SAVE_ERRNO( 906 msyslog(LOG_ERR, 907 "refclock_setup fd %d TCGETA: %m", 908 fd); 909 ) 910 return FALSE; | 868 msyslog(LOG_ERR, 869 "refclock_open: fd %d TCGETA failed: %m", fd); 870 return (0); |
911 } 912 913 /* 914 * Set canonical mode and local connection; set specified speed, 915 * 8 bits and no parity; map CR to NL; ignore break. 916 */ | 871 } 872 873 /* 874 * Set canonical mode and local connection; set specified speed, 875 * 8 bits and no parity; map CR to NL; ignore break. 876 */ |
917 if (speed) { 918 u_int ltemp = 0; | 877 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 878 ttyp->c_oflag = 0; 879 ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 880 ttyp->c_lflag = ICANON; 881 ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; |
919 | 882 |
920 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 921 ttyp->c_oflag = 0; 922 ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 923 for (i = 0; i < NCCS; ++i) 924 ttyp->c_cc[i] = '\0'; 925 926#if defined(TIOCMGET) && !defined(SCO5_CLOCK) 927 928 /* 929 * If we have modem control, check to see if modem leads 930 * are active; if so, set remote connection. This is 931 * necessary for the kernel pps mods to work. 932 */ 933 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 934 msyslog(LOG_ERR, 935 "refclock_setup fd %d TIOCMGET: %m", fd); 936#ifdef DEBUG 937 if (debug) 938 printf("refclock_setup fd %d modem status: %x\n", 939 fd, ltemp); 940#endif 941 if (ltemp & TIOCM_DSR) 942 ttyp->c_cflag &= ~CLOCAL; 943#endif /* TIOCMGET */ 944 } 945 | |
946 /* | 883 /* |
947 * Set raw and echo modes. These can be changed on-fly. | 884 * Some special cases |
948 */ | 885 */ |
949 ttyp->c_lflag = ICANON; 950 if (lflags & LDISC_RAW) { 951 ttyp->c_lflag = 0; | 886 if (flags & LDISC_RAW) { |
952 ttyp->c_iflag = 0; | 887 ttyp->c_iflag = 0; |
953 ttyp->c_cc[VMIN] = 1; | 888 ttyp->c_lflag = 0; |
954 } | 889 } |
890#ifdef TIOCMGET 891 /* 892 * If we have modem control, check to see if modem leads are 893 * active; if so, set remote connection. This is necessary for 894 * the kernel pps mods to work. 895 */ 896 ltemp = 0; 897 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 898 msyslog(LOG_ERR, 899 "refclock_open: fd %d TIOCMGET failed: %m", fd); 900#ifdef DEBUG 901 if (debug) 902 printf("refclock_open: fd %d modem status %lx\n", 903 fd, ltemp); 904#endif 905 if (ltemp & TIOCM_DSR) 906 ttyp->c_cflag &= ~CLOCAL; 907#endif /* TIOCMGET */ |
|
955 if (ioctl(fd, TCSETA, ttyp) < 0) { | 908 if (ioctl(fd, TCSETA, ttyp) < 0) { |
956 SAVE_ERRNO( 957 msyslog(LOG_ERR, 958 "refclock_setup fd %d TCSETA: %m", fd); 959 ) 960 return FALSE; | 909 msyslog(LOG_ERR, 910 "refclock_open: fd %d TCSETA failed: %m", fd); 911 return (0); |
961 } 962#endif /* HAVE_SYSV_TTYS */ 963 964#ifdef HAVE_BSD_TTYS 965 966 /* 967 * 4.3bsd serial line parameters (sgttyb interface) 968 */ 969 if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { | 912 } 913#endif /* HAVE_SYSV_TTYS */ 914 915#ifdef HAVE_BSD_TTYS 916 917 /* 918 * 4.3bsd serial line parameters (sgttyb interface) 919 */ 920 if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { |
970 SAVE_ERRNO( 971 msyslog(LOG_ERR, 972 "refclock_setup fd %d TIOCGETP: %m", 973 fd); 974 ) 975 return FALSE; | 921 msyslog(LOG_ERR, 922 "refclock_open: fd %d TIOCGETP %m", fd); 923 return (0); |
976 } | 924 } |
977 if (speed) 978 ttyp->sg_ispeed = ttyp->sg_ospeed = speed; | 925 ttyp->sg_ispeed = ttyp->sg_ospeed = speed; |
979 ttyp->sg_flags = EVENP | ODDP | CRMOD; 980 if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { | 926 ttyp->sg_flags = EVENP | ODDP | CRMOD; 927 if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { |
981 SAVE_ERRNO( 982 msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m"); 983 ) 984 return FALSE; | 928 msyslog(LOG_ERR, 929 "refclock_open: TIOCSETP failed: %m"); 930 return (0); |
985 } 986#endif /* HAVE_BSD_TTYS */ | 931 } 932#endif /* HAVE_BSD_TTYS */ |
987 return(1); | 933 if (!refclock_ioctl(fd, flags)) { 934 (void)close(fd); 935 msyslog(LOG_ERR, 936 "refclock_open: fd %d ioctl failed: %m", fd); 937 return (0); 938 } 939 940 /* 941 * If this is the PPS device, so say and initialize the thing. 942 */ 943 if (strcmp(dev, pps_device) == 0) 944 (void)refclock_ioctl(fd, LDISC_PPS); 945 return (fd); |
988} 989#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ | 946} 947#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ |
948#endif /* SYS_VXWORKS SYS_WINNT */ |
|
990 | 949 |
991 | |
992/* 993 * refclock_ioctl - set serial port control functions 994 * 995 * This routine attempts to hide the internal, system-specific details 996 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 997 * (sgtty) interfaces with varying degrees of success. The routine sets | 950/* 951 * refclock_ioctl - set serial port control functions 952 * 953 * This routine attempts to hide the internal, system-specific details 954 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 955 * (sgtty) interfaces with varying degrees of success. The routine sets |
998 * up optional features such as tty_clk. The routine returns TRUE if 999 * successful. | 956 * up optional features such as tty_clk, ppsclock and ppsapi, as well as 957 * their many other variants. The routine returns 1 if success and 0 if 958 * failure. |
1000 */ 1001int 1002refclock_ioctl( | 959 */ 960int 961refclock_ioctl( |
1003 int fd, /* file descriptor */ 1004 u_int lflags /* line discipline flags */ | 962 int fd, /* file descriptor */ 963 int flags /* line discipline flags */ |
1005 ) 1006{ | 964 ) 965{ |
966 /* simply return 1 if no UNIX line discipline is supported */ 967#if !defined SYS_VXWORKS && !defined SYS_WINNT 968#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 969 970#ifdef TTYCLK 971#ifdef HAVE_TERMIOS 972 struct termios ttyb, *ttyp; 973#endif /* HAVE_TERMIOS */ 974#ifdef HAVE_SYSV_TTYS 975 struct termio ttyb, *ttyp; 976#endif /* HAVE_SYSV_TTYS */ 977#ifdef HAVE_BSD_TTYS 978 struct sgttyb ttyb, *ttyp; 979#endif /* HAVE_BSD_TTYS */ 980#endif /* TTYCLK */ 981 982#ifdef DEBUG 983 if (debug) 984 printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags); 985#endif 986 |
|
1007 /* | 987 /* |
1008 * simply return TRUE if no UNIX line discipline is supported | 988 * The following sections select optional features, such as 989 * modem control, PPS capture and so forth. Some require 990 * specific operating system support in the form of STREAMS 991 * modules, which can be loaded and unloaded at run time without 992 * rebooting the kernel. The STREAMS modules require System 993 * V STREAMS support. The checking frenzy is attenuated here, 994 * since the device is already open. 995 * 996 * Note that the tty_clk and ppsclock modules are optional; if 997 * configured and unavailable, the dang thing still works, but 998 * the accuracy improvement using them will not be available. 999 * The only known implmentations of these moldules are specific 1000 * to SunOS 4.x. Use the ppsclock module ONLY with Sun baseboard 1001 * ttya or ttyb. Using it with the SPIF multipexor crashes the 1002 * kernel. 1003 * 1004 * The preferred way to capture PPS timestamps is using the 1005 * ppsapi interface, which is machine independent. The SunOS 4.x 1006 * and Digital Unix 4.x interfaces use STREAMS modules and 1007 * support both the ppsapi specification and ppsclock 1008 * functionality, but other systems may vary widely. |
1009 */ | 1009 */ |
1010 DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags)); | 1010 if (flags == 0) 1011 return (1); 1012#if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS)) 1013 if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) { 1014 msyslog(LOG_ERR, 1015 "refclock_ioctl: unsupported terminal interface"); 1016 return (0); 1017 } 1018#endif /* HAVE_TERMIOS HAVE_BSD_TTYS */ 1019#ifdef TTYCLK 1020 ttyp = &ttyb; 1021#endif /* TTYCLK */ |
1011 | 1022 |
1012 return TRUE; 1013} 1014#endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */ | 1023 /* 1024 * The following features may or may not require System V 1025 * STREAMS support, depending on the particular implementation. 1026 */ 1027#if defined(TTYCLK) 1028 /* 1029 * The TTYCLK option provides timestamping at the driver level. 1030 * It requires the tty_clk streams module and System V STREAMS 1031 * support. If not available, don't complain. 1032 */ 1033 if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) { 1034 int rval = 0; |
1015 | 1035 |
1036 if (ioctl(fd, I_PUSH, "clk") < 0) { 1037 msyslog(LOG_NOTICE, 1038 "refclock_ioctl: I_PUSH clk failed: %m"); 1039 } else { 1040 char *str; |
|
1016 | 1041 |
1042 if (flags & LDISC_CLKPPS) 1043 str = "\377"; 1044 else if (flags & LDISC_ACTS) 1045 str = "*"; 1046 else 1047 str = "\n"; 1048#ifdef CLK_SETSTR 1049 if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0) 1050 msyslog(LOG_ERR, 1051 "refclock_ioctl: CLK_SETSTR failed: %m"); 1052 if (debug) 1053 printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n", 1054 fd, rval, str); 1055#endif 1056 } 1057 } 1058#endif /* TTYCLK */ 1059 1060#if defined(PPS) && !defined(HAVE_PPSAPI) 1061 /* 1062 * The PPS option provides timestamping at the driver level. 1063 * It uses a 1-pps signal and level converter (gadget box) and 1064 * requires the ppsclock streams module and System V STREAMS 1065 * support. This option has been superseded by the ppsapi 1066 * option and may be withdrawn in future. 1067 */ 1068 if (flags & LDISC_PPS) { 1069 int rval = 0; 1070#ifdef HAVE_TIOCSPPS /* Solaris */ 1071 int one = 1; 1072#endif /* HAVE_TIOCSPPS */ 1073 1074 if (fdpps > 0) { 1075 msyslog(LOG_ERR, 1076 "refclock_ioctl: PPS already configured"); 1077 return (0); 1078 } 1079#ifdef HAVE_TIOCSPPS /* Solaris */ 1080 if (ioctl(fd, TIOCSPPS, &one) < 0) { 1081 msyslog(LOG_NOTICE, 1082 "refclock_ioctl: TIOCSPPS failed: %m"); 1083 return (0); 1084 } 1085 if (debug) 1086 printf("refclock_ioctl: fd %d TIOCSPPS %d\n", 1087 fd, rval); 1088#else 1089 if (ioctl(fd, I_PUSH, "ppsclock") < 0) { 1090 msyslog(LOG_NOTICE, 1091 "refclock_ioctl: I_PUSH ppsclock failed: %m"); 1092 return (0); 1093 } 1094 if (debug) 1095 printf("refclock_ioctl: fd %d ppsclock %d\n", 1096 fd, rval); 1097#endif /* not HAVE_TIOCSPPS */ 1098 fdpps = fd; 1099 } 1100#endif /* PPS HAVE_PPSAPI */ 1101 1102#ifdef HAVE_PPSAPI 1103 /* 1104 * The PPSAPI option provides timestamping at the driver level. 1105 * It uses a 1-pps signal and level converter (gadget box) and 1106 * requires ppsapi compiled into the kernel on non STREAMS 1107 * systems. This is the preferred way to capture PPS timestamps 1108 * and is expected to become an IETF cross-platform standard. 1109 */ 1110 if (flags & (LDISC_PPS | LDISC_CLKPPS)) { 1111 pps_params_t pp; 1112 int mode, temp; 1113 pps_handle_t handle; 1114 1115 memset((char *)&pp, 0, sizeof(pp)); 1116 if (fdpps > 0) { 1117 msyslog(LOG_ERR, 1118 "refclock_ioctl: ppsapi already configured"); 1119 return (0); 1120 } 1121 if (time_pps_create(fd, &handle) < 0) { 1122 msyslog(LOG_ERR, 1123 "refclock_ioctl: time_pps_create failed: %m"); 1124 return (0); 1125 } 1126 if (time_pps_getcap(handle, &mode) < 0) { 1127 msyslog(LOG_ERR, 1128 "refclock_ioctl: time_pps_getcap failed: %m"); 1129 return (0); 1130 } 1131 pp.mode = mode & PPS_CAPTUREBOTH; 1132 if (time_pps_setparams(handle, &pp) < 0) { 1133 msyslog(LOG_ERR, 1134 "refclock_ioctl: time_pps_setparams failed: %m"); 1135 return (0); 1136 } 1137 if (!pps_hardpps) 1138 temp = 0; 1139 else if (pps_assert) 1140 temp = mode & PPS_CAPTUREASSERT; 1141 else 1142 temp = mode & PPS_CAPTURECLEAR; 1143 if (time_pps_kcbind(handle, PPS_KC_HARDPPS, temp, 1144 PPS_TSFMT_TSPEC) < 0) { 1145 msyslog(LOG_ERR, 1146 "refclock_ioctl: time_pps_kcbind failed: %m"); 1147 return (0); 1148 } 1149 (void)time_pps_getparams(handle, &pp); 1150 fdpps = (int)handle; 1151 if (debug) 1152 printf( 1153 "refclock_ioctl: fd %d ppsapi vers %d mode 0x%x cap 0x%x\n", 1154 fdpps, pp.api_version, pp.mode, mode); 1155 } 1156#endif /* HAVE_PPSAPI */ 1157#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 1158#endif /* SYS_VXWORKS SYS_WINNT */ 1159 return (1); 1160} 1161 |
|
1017/* 1018 * refclock_control - set and/or return clock values 1019 * 1020 * This routine is used mainly for debugging. It returns designated 1021 * values from the interface structure that can be displayed using 1022 * ntpdc and the clockstat command. It can also be used to initialize 1023 * configuration variables, such as fudgetimes, fudgevalues, reference 1024 * ID and stratum. 1025 */ 1026void 1027refclock_control( | 1162/* 1163 * refclock_control - set and/or return clock values 1164 * 1165 * This routine is used mainly for debugging. It returns designated 1166 * values from the interface structure that can be displayed using 1167 * ntpdc and the clockstat command. It can also be used to initialize 1168 * configuration variables, such as fudgetimes, fudgevalues, reference 1169 * ID and stratum. 1170 */ 1171void 1172refclock_control( |
1028 sockaddr_u *srcadr, 1029 const struct refclockstat *in, | 1173 struct sockaddr_in *srcadr, 1174 struct refclockstat *in, |
1030 struct refclockstat *out 1031 ) 1032{ 1033 struct peer *peer; 1034 struct refclockproc *pp; 1035 u_char clktype; 1036 int unit; 1037 1038 /* 1039 * Check for valid address and running peer 1040 */ 1041 if (!ISREFCLOCKADR(srcadr)) 1042 return; | 1175 struct refclockstat *out 1176 ) 1177{ 1178 struct peer *peer; 1179 struct refclockproc *pp; 1180 u_char clktype; 1181 int unit; 1182 1183 /* 1184 * Check for valid address and running peer 1185 */ 1186 if (!ISREFCLOCKADR(srcadr)) 1187 return; |
1043 | |
1044 clktype = (u_char)REFCLOCKTYPE(srcadr); 1045 unit = REFCLOCKUNIT(srcadr); | 1188 clktype = (u_char)REFCLOCKTYPE(srcadr); 1189 unit = REFCLOCKUNIT(srcadr); |
1046 1047 peer = findexistingpeer(srcadr, NULL, NULL, -1, 0); 1048 1049 if (NULL == peer) | 1190 if (clktype >= num_refclock_conf || unit >= MAXUNIT) |
1050 return; | 1191 return; |
1051 1052 INSIST(peer->procptr != NULL); | 1192 if (!(peer = typeunit[clktype][unit])) 1193 return; |
1053 pp = peer->procptr; 1054 1055 /* 1056 * Initialize requested data 1057 */ | 1194 pp = peer->procptr; 1195 1196 /* 1197 * Initialize requested data 1198 */ |
1058 if (in != NULL) { | 1199 if (in != 0) { |
1059 if (in->haveflags & CLK_HAVETIME1) 1060 pp->fudgetime1 = in->fudgetime1; 1061 if (in->haveflags & CLK_HAVETIME2) 1062 pp->fudgetime2 = in->fudgetime2; 1063 if (in->haveflags & CLK_HAVEVAL1) | 1200 if (in->haveflags & CLK_HAVETIME1) 1201 pp->fudgetime1 = in->fudgetime1; 1202 if (in->haveflags & CLK_HAVETIME2) 1203 pp->fudgetime2 = in->fudgetime2; 1204 if (in->haveflags & CLK_HAVEVAL1) |
1064 peer->stratum = pp->stratum = (u_char)in->fudgeval1; | 1205 peer->stratum = (u_char) in->fudgeval1; |
1065 if (in->haveflags & CLK_HAVEVAL2) | 1206 if (in->haveflags & CLK_HAVEVAL2) |
1066 peer->refid = pp->refid = in->fudgeval2; | 1207 pp->refid = in->fudgeval2; 1208 if (peer->stratum <= 1) 1209 peer->refid = pp->refid; 1210 else 1211 peer->refid = peer->srcadr.sin_addr.s_addr; |
1067 if (in->haveflags & CLK_HAVEFLAG1) { 1068 pp->sloppyclockflag &= ~CLK_FLAG1; 1069 pp->sloppyclockflag |= in->flags & CLK_FLAG1; 1070 } 1071 if (in->haveflags & CLK_HAVEFLAG2) { 1072 pp->sloppyclockflag &= ~CLK_FLAG2; 1073 pp->sloppyclockflag |= in->flags & CLK_FLAG2; 1074 } --- 5 unchanged lines hidden (view full) --- 1080 pp->sloppyclockflag &= ~CLK_FLAG4; 1081 pp->sloppyclockflag |= in->flags & CLK_FLAG4; 1082 } 1083 } 1084 1085 /* 1086 * Readback requested data 1087 */ | 1212 if (in->haveflags & CLK_HAVEFLAG1) { 1213 pp->sloppyclockflag &= ~CLK_FLAG1; 1214 pp->sloppyclockflag |= in->flags & CLK_FLAG1; 1215 } 1216 if (in->haveflags & CLK_HAVEFLAG2) { 1217 pp->sloppyclockflag &= ~CLK_FLAG2; 1218 pp->sloppyclockflag |= in->flags & CLK_FLAG2; 1219 } --- 5 unchanged lines hidden (view full) --- 1225 pp->sloppyclockflag &= ~CLK_FLAG4; 1226 pp->sloppyclockflag |= in->flags & CLK_FLAG4; 1227 } 1228 } 1229 1230 /* 1231 * Readback requested data 1232 */ |
1088 if (out != NULL) { 1089 out->fudgeval1 = pp->stratum; 1090 out->fudgeval2 = pp->refid; 1091 out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; | 1233 if (out != 0) { 1234 out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | 1235 CLK_HAVEVAL2 | CLK_HAVEFLAG4; |
1092 out->fudgetime1 = pp->fudgetime1; | 1236 out->fudgetime1 = pp->fudgetime1; |
1093 if (0.0 != out->fudgetime1) 1094 out->haveflags |= CLK_HAVETIME1; | |
1095 out->fudgetime2 = pp->fudgetime2; | 1237 out->fudgetime2 = pp->fudgetime2; |
1096 if (0.0 != out->fudgetime2) 1097 out->haveflags |= CLK_HAVETIME2; | 1238 out->fudgeval1 = peer->stratum; 1239 out->fudgeval2 = pp->refid; |
1098 out->flags = (u_char) pp->sloppyclockflag; | 1240 out->flags = (u_char) pp->sloppyclockflag; |
1099 if (CLK_FLAG1 & out->flags) 1100 out->haveflags |= CLK_HAVEFLAG1; 1101 if (CLK_FLAG2 & out->flags) 1102 out->haveflags |= CLK_HAVEFLAG2; 1103 if (CLK_FLAG3 & out->flags) 1104 out->haveflags |= CLK_HAVEFLAG3; 1105 if (CLK_FLAG4 & out->flags) 1106 out->haveflags |= CLK_HAVEFLAG4; | |
1107 1108 out->timereset = current_time - pp->timestarted; 1109 out->polls = pp->polls; 1110 out->noresponse = pp->noreply; 1111 out->badformat = pp->badformat; 1112 out->baddata = pp->baddata; 1113 1114 out->lastevent = pp->lastevent; 1115 out->currentstatus = pp->currentstatus; 1116 out->type = pp->type; 1117 out->clockdesc = pp->clockdesc; | 1241 1242 out->timereset = current_time - pp->timestarted; 1243 out->polls = pp->polls; 1244 out->noresponse = pp->noreply; 1245 out->badformat = pp->badformat; 1246 out->baddata = pp->baddata; 1247 1248 out->lastevent = pp->lastevent; 1249 out->currentstatus = pp->currentstatus; 1250 out->type = pp->type; 1251 out->clockdesc = pp->clockdesc; |
1118 out->lencode = (u_short)pp->lencode; | 1252 out->lencode = pp->lencode; |
1119 out->p_lastcode = pp->a_lastcode; 1120 } 1121 1122 /* 1123 * Give the stuff to the clock 1124 */ 1125 if (refclock_conf[clktype]->clock_control != noentry) 1126 (refclock_conf[clktype]->clock_control)(unit, in, out, peer); --- 4 unchanged lines hidden (view full) --- 1131 * refclock_buginfo - return debugging info 1132 * 1133 * This routine is used mainly for debugging. It returns designated 1134 * values from the interface structure that can be displayed using 1135 * ntpdc and the clkbug command. 1136 */ 1137void 1138refclock_buginfo( | 1253 out->p_lastcode = pp->a_lastcode; 1254 } 1255 1256 /* 1257 * Give the stuff to the clock 1258 */ 1259 if (refclock_conf[clktype]->clock_control != noentry) 1260 (refclock_conf[clktype]->clock_control)(unit, in, out, peer); --- 4 unchanged lines hidden (view full) --- 1265 * refclock_buginfo - return debugging info 1266 * 1267 * This routine is used mainly for debugging. It returns designated 1268 * values from the interface structure that can be displayed using 1269 * ntpdc and the clkbug command. 1270 */ 1271void 1272refclock_buginfo( |
1139 sockaddr_u *srcadr, /* clock address */ | 1273 struct sockaddr_in *srcadr, /* clock address */ |
1140 struct refclockbug *bug /* output structure */ 1141 ) 1142{ 1143 struct peer *peer; 1144 struct refclockproc *pp; | 1274 struct refclockbug *bug /* output structure */ 1275 ) 1276{ 1277 struct peer *peer; 1278 struct refclockproc *pp; |
1145 int clktype; | 1279 u_char clktype; |
1146 int unit; | 1280 int unit; |
1147 unsigned u; | 1281 int i; |
1148 1149 /* 1150 * Check for valid address and peer structure 1151 */ 1152 if (!ISREFCLOCKADR(srcadr)) 1153 return; | 1282 1283 /* 1284 * Check for valid address and peer structure 1285 */ 1286 if (!ISREFCLOCKADR(srcadr)) 1287 return; |
1154 | |
1155 clktype = (u_char) REFCLOCKTYPE(srcadr); 1156 unit = REFCLOCKUNIT(srcadr); | 1288 clktype = (u_char) REFCLOCKTYPE(srcadr); 1289 unit = REFCLOCKUNIT(srcadr); |
1157 1158 peer = findexistingpeer(srcadr, NULL, NULL, -1, 0); 1159 1160 if (NULL == peer || NULL == peer->procptr) | 1290 if (clktype >= num_refclock_conf || unit >= MAXUNIT) |
1161 return; | 1291 return; |
1162 | 1292 if (!(peer = typeunit[clktype][unit])) 1293 return; |
1163 pp = peer->procptr; 1164 1165 /* 1166 * Copy structure values 1167 */ 1168 bug->nvalues = 8; 1169 bug->svalues = 0x0000003f; 1170 bug->values[0] = pp->year; 1171 bug->values[1] = pp->day; 1172 bug->values[2] = pp->hour; 1173 bug->values[3] = pp->minute; 1174 bug->values[4] = pp->second; | 1294 pp = peer->procptr; 1295 1296 /* 1297 * Copy structure values 1298 */ 1299 bug->nvalues = 8; 1300 bug->svalues = 0x0000003f; 1301 bug->values[0] = pp->year; 1302 bug->values[1] = pp->day; 1303 bug->values[2] = pp->hour; 1304 bug->values[3] = pp->minute; 1305 bug->values[4] = pp->second; |
1175 bug->values[5] = pp->nsec; | 1306 bug->values[5] = pp->msec; |
1176 bug->values[6] = pp->yearstart; 1177 bug->values[7] = pp->coderecv; 1178 bug->stimes = 0xfffffffc; 1179 bug->times[0] = pp->lastref; 1180 bug->times[1] = pp->lastrec; | 1307 bug->values[6] = pp->yearstart; 1308 bug->values[7] = pp->coderecv; 1309 bug->stimes = 0xfffffffc; 1310 bug->times[0] = pp->lastref; 1311 bug->times[1] = pp->lastrec; |
1181 for (u = 2; u < bug->ntimes; u++) 1182 DTOLFP(pp->filter[u - 2], &bug->times[u]); | 1312 for (i = 2; i < (int)bug->ntimes; i++) 1313 DTOLFP(pp->filter[i - 2], &bug->times[i]); |
1183 1184 /* 1185 * Give the stuff to the clock 1186 */ 1187 if (refclock_conf[clktype]->clock_buginfo != noentry) 1188 (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 1189} 1190 | 1314 1315 /* 1316 * Give the stuff to the clock 1317 */ 1318 if (refclock_conf[clktype]->clock_buginfo != noentry) 1319 (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 1320} 1321 |
1191 1192#ifdef HAVE_PPSAPI 1193/* 1194 * refclock_ppsapi - initialize/update ppsapi 1195 * 1196 * This routine is called after the fudge command to open the PPSAPI 1197 * interface for later parameter setting after the fudge command. 1198 */ 1199int 1200refclock_ppsapi( 1201 int fddev, /* fd device */ 1202 struct refclock_atom *ap /* atom structure pointer */ 1203 ) 1204{ 1205 if (ap->handle == 0) { 1206 if (time_pps_create(fddev, &ap->handle) < 0) { 1207 msyslog(LOG_ERR, 1208 "refclock_ppsapi: time_pps_create: %m"); 1209 return (0); 1210 } 1211 } 1212 return (1); 1213} 1214 1215 1216/* 1217 * refclock_params - set ppsapi parameters 1218 * 1219 * This routine is called to set the PPSAPI parameters after the fudge 1220 * command. 1221 */ 1222int 1223refclock_params( 1224 int mode, /* mode bits */ 1225 struct refclock_atom *ap /* atom structure pointer */ 1226 ) 1227{ 1228 ZERO(ap->pps_params); 1229 ap->pps_params.api_version = PPS_API_VERS_1; 1230 1231 /* 1232 * Solaris serial ports provide PPS pulse capture only on the 1233 * assert edge. FreeBSD serial ports provide capture on the 1234 * clear edge, while FreeBSD parallel ports provide capture 1235 * on the assert edge. Your mileage may vary. 1236 */ 1237 if (mode & CLK_FLAG2) 1238 ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR; 1239 else 1240 ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT; 1241 if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) { 1242 msyslog(LOG_ERR, 1243 "refclock_params: time_pps_setparams: %m"); 1244 return (0); 1245 } 1246 1247 /* 1248 * If flag3 is lit, select the kernel PPS if we can. 1249 */ 1250 if (mode & CLK_FLAG3) { 1251 if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS, 1252 ap->pps_params.mode & ~PPS_TSFMT_TSPEC, 1253 PPS_TSFMT_TSPEC) < 0) { 1254 msyslog(LOG_ERR, 1255 "refclock_params: time_pps_kcbind: %m"); 1256 return (0); 1257 } 1258 hardpps_enable = 1; 1259 } 1260 return (1); 1261} 1262 1263 1264/* 1265 * refclock_pps - called once per second 1266 * 1267 * This routine is called once per second. It snatches the PPS 1268 * timestamp from the kernel and saves the sign-extended fraction in 1269 * a circular buffer for processing at the next poll event. 1270 */ 1271int 1272refclock_pps( 1273 struct peer *peer, /* peer structure pointer */ 1274 struct refclock_atom *ap, /* atom structure pointer */ 1275 int mode /* mode bits */ 1276 ) 1277{ 1278 struct refclockproc *pp; 1279 pps_info_t pps_info; 1280 struct timespec timeout; 1281 double dtemp; 1282 1283 /* 1284 * We require the clock to be synchronized before setting the 1285 * parameters. When the parameters have been set, fetch the 1286 * most recent PPS timestamp. 1287 */ 1288 pp = peer->procptr; 1289 if (ap->handle == 0) 1290 return (0); 1291 1292 if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) { 1293 if (refclock_params(pp->sloppyclockflag, ap) < 1) 1294 return (0); 1295 } 1296 timeout.tv_sec = 0; 1297 timeout.tv_nsec = 0; 1298 ZERO(pps_info); 1299 if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, 1300 &timeout) < 0) { 1301 refclock_report(peer, CEVNT_FAULT); 1302 return (0); 1303 } 1304 timeout = ap->ts; 1305 if (ap->pps_params.mode & PPS_CAPTUREASSERT) 1306 ap->ts = pps_info.assert_timestamp; 1307 else if (ap->pps_params.mode & PPS_CAPTURECLEAR) 1308 ap->ts = pps_info.clear_timestamp; 1309 else 1310 return (0); 1311 1312 if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout))) 1313 return (0); 1314 1315 /* 1316 * Convert to signed fraction offset and stuff in median filter. 1317 */ 1318 pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; 1319 dtemp = ap->ts.tv_nsec / 1e9; 1320 pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); 1321 if (dtemp > .5) 1322 dtemp -= 1.; 1323 SAMPLE(-dtemp + pp->fudgetime1); 1324#ifdef DEBUG 1325 if (debug > 1) 1326 printf("refclock_pps: %lu %f %f\n", current_time, 1327 dtemp, pp->fudgetime1); 1328#endif 1329 return (1); 1330} 1331#endif /* HAVE_PPSAPI */ | |
1332#endif /* REFCLOCK */ | 1322#endif /* REFCLOCK */ |