154359Sroberto/* 282498Sroberto * refclock_ulink - clock driver for Ultralink WWVB receiver 354359Sroberto */ 454359Sroberto 554359Sroberto#ifdef HAVE_CONFIG_H 654359Sroberto#include <config.h> 754359Sroberto#endif 854359Sroberto 954359Sroberto#if defined(REFCLOCK) && defined(CLOCK_ULINK) 1054359Sroberto 1154359Sroberto#include <stdio.h> 1254359Sroberto#include <ctype.h> 1354359Sroberto 1454359Sroberto#include "ntpd.h" 1554359Sroberto#include "ntp_io.h" 1654359Sroberto#include "ntp_refclock.h" 1754359Sroberto#include "ntp_stdlib.h" 1854359Sroberto 19182007Sroberto/* This driver supports ultralink Model 320,325,330,331,332 WWVB radios 2054359Sroberto * 2182498Sroberto * this driver was based on the refclock_wwvb.c driver 2282498Sroberto * in the ntp distribution. 2354359Sroberto * 2482498Sroberto * Fudge Factors 2554359Sroberto * 2682498Sroberto * fudge flag1 0 don't poll clock 2782498Sroberto * 1 send poll character 2854359Sroberto * 2982498Sroberto * revision history: 3082498Sroberto * 99/9/09 j.c.lang original edit's 3182498Sroberto * 99/9/11 j.c.lang changed timecode parse to 3282498Sroberto * match what the radio actually 3382498Sroberto * sends. 3482498Sroberto * 99/10/11 j.c.lang added support for continous 3582498Sroberto * time code mode (dipsw2) 3682498Sroberto * 99/11/26 j.c.lang added support for 320 decoder 3782498Sroberto * (taken from Dave Strout's 3882498Sroberto * Model 320 driver) 3982498Sroberto * 99/11/29 j.c.lang added fudge flag 1 to control 4082498Sroberto * clock polling 4182498Sroberto * 99/12/15 j.c.lang fixed 320 quality flag 4282498Sroberto * 01/02/21 s.l.smith fixed 33x quality flag 4382498Sroberto * added more debugging stuff 4482498Sroberto * updated 33x time code explanation 45182007Sroberto * 04/01/23 frank migge added support for 325 decoder 46182007Sroberto * (tested with ULM325.F) 4754359Sroberto * 4882498Sroberto * Questions, bugs, ideas send to: 4982498Sroberto * Joseph C. Lang 5082498Sroberto * tcnojl1@earthlink.net 5154359Sroberto * 5282498Sroberto * Dave Strout 5382498Sroberto * dstrout@linuxfoundry.com 5482498Sroberto * 55182007Sroberto * Frank Migge 56182007Sroberto * frank.migge@oracle.com 5782498Sroberto * 58182007Sroberto * 5982498Sroberto * on the Ultralink model 33X decoder Dip switch 2 controls 6082498Sroberto * polled or continous timecode 61182007Sroberto * set fudge flag1 if using polled (needed for model 320 and 325) 6282498Sroberto * dont set fudge flag1 if dip switch 2 is set on model 33x decoder 6382498Sroberto*/ 6454359Sroberto 6582498Sroberto 6654359Sroberto/* 6754359Sroberto * Interface definitions 6854359Sroberto */ 6982498Sroberto#define DEVICE "/dev/wwvb%d" /* device name and unit */ 7054359Sroberto#define SPEED232 B9600 /* uart speed (9600 baud) */ 7182498Sroberto#define PRECISION (-10) /* precision assumed (about 10 ms) */ 7282498Sroberto#define REFID "WWVB" /* reference ID */ 7354359Sroberto#define DESCRIPTION "Ultralink WWVB Receiver" /* WRU */ 7454359Sroberto 75182007Sroberto#define LEN33X 32 /* timecode length Model 33X and 325 */ 7682498Sroberto#define LEN320 24 /* timecode length Model 320 */ 7754359Sroberto 78182007Sroberto#define SIGLCHAR33x 'S' /* signal strength identifier char 325 */ 79182007Sroberto#define SIGLCHAR325 'R' /* signal strength identifier char 33x */ 80182007Sroberto 8154359Sroberto/* 8282498Sroberto * unit control structure 8354359Sroberto */ 8454359Srobertostruct ulinkunit { 8554359Sroberto u_char tcswitch; /* timecode switch */ 8654359Sroberto l_fp laststamp; /* last receive timestamp */ 8754359Sroberto}; 8854359Sroberto 8954359Sroberto/* 9054359Sroberto * Function prototypes 9154359Sroberto */ 92290001Sglebiusstatic int ulink_start (int, struct peer *); 93290001Sglebiusstatic void ulink_shutdown (int, struct peer *); 94290001Sglebiusstatic void ulink_receive (struct recvbuf *); 95290001Sglebiusstatic void ulink_poll (int, struct peer *); 9654359Sroberto 9754359Sroberto/* 9854359Sroberto * Transfer vector 9954359Sroberto */ 10054359Srobertostruct refclock refclock_ulink = { 10154359Sroberto ulink_start, /* start up driver */ 10254359Sroberto ulink_shutdown, /* shut down driver */ 10354359Sroberto ulink_poll, /* transmit poll message */ 10482498Sroberto noentry, /* not used */ 10582498Sroberto noentry, /* not used */ 10682498Sroberto noentry, /* not used */ 10782498Sroberto NOFLAGS 10854359Sroberto}; 10954359Sroberto 11054359Sroberto 11154359Sroberto/* 11254359Sroberto * ulink_start - open the devices and initialize data for processing 11354359Sroberto */ 11454359Srobertostatic int 11554359Srobertoulink_start( 11654359Sroberto int unit, 11754359Sroberto struct peer *peer 11854359Sroberto ) 11954359Sroberto{ 12054359Sroberto register struct ulinkunit *up; 12154359Sroberto struct refclockproc *pp; 12282498Sroberto int fd; 12354359Sroberto char device[20]; 12482498Sroberto 12554359Sroberto /* 12654359Sroberto * Open serial port. Use CLK line discipline, if available. 12754359Sroberto */ 128290001Sglebius snprintf(device, sizeof(device), DEVICE, unit); 129290001Sglebius fd = refclock_open(device, SPEED232, LDISC_CLK); 130290001Sglebius if (fd <= 0) 13154359Sroberto return (0); 13254359Sroberto 13354359Sroberto /* 13454359Sroberto * Allocate and initialize unit structure 13554359Sroberto */ 136290001Sglebius up = emalloc(sizeof(struct ulinkunit)); 137290001Sglebius memset(up, 0, sizeof(struct ulinkunit)); 13854359Sroberto pp = peer->procptr; 13954359Sroberto pp->io.clock_recv = ulink_receive; 140290001Sglebius pp->io.srcclock = peer; 14154359Sroberto pp->io.datalen = 0; 14254359Sroberto pp->io.fd = fd; 14354359Sroberto if (!io_addclock(&pp->io)) { 144290001Sglebius close(fd); 145290001Sglebius pp->io.fd = -1; 14654359Sroberto free(up); 14754359Sroberto return (0); 14854359Sroberto } 149290001Sglebius pp->unitptr = up; 15054359Sroberto 15154359Sroberto /* 15254359Sroberto * Initialize miscellaneous variables 15354359Sroberto */ 15454359Sroberto peer->precision = PRECISION; 15554359Sroberto pp->clockdesc = DESCRIPTION; 15654359Sroberto memcpy((char *)&pp->refid, REFID, 4); 15754359Sroberto return (1); 15854359Sroberto} 15954359Sroberto 16054359Sroberto 16154359Sroberto/* 16254359Sroberto * ulink_shutdown - shut down the clock 16354359Sroberto */ 16454359Srobertostatic void 16554359Srobertoulink_shutdown( 16654359Sroberto int unit, 16754359Sroberto struct peer *peer 16854359Sroberto ) 16954359Sroberto{ 17054359Sroberto register struct ulinkunit *up; 17154359Sroberto struct refclockproc *pp; 17254359Sroberto 17354359Sroberto pp = peer->procptr; 174290001Sglebius up = pp->unitptr; 175290001Sglebius if (pp->io.fd != -1) 176290001Sglebius io_closeclock(&pp->io); 177290001Sglebius if (up != NULL) 178290001Sglebius free(up); 17954359Sroberto} 18054359Sroberto 18154359Sroberto 18254359Sroberto/* 18354359Sroberto * ulink_receive - receive data from the serial interface 18454359Sroberto */ 18554359Srobertostatic void 18654359Srobertoulink_receive( 18754359Sroberto struct recvbuf *rbufp 18854359Sroberto ) 18954359Sroberto{ 19054359Sroberto struct ulinkunit *up; 19154359Sroberto struct refclockproc *pp; 19254359Sroberto struct peer *peer; 19354359Sroberto 194290001Sglebius l_fp trtmp; /* arrival timestamp */ 195290001Sglebius int quality = INT_MAX; /* quality indicator */ 196290001Sglebius int temp; /* int temp */ 197290001Sglebius char syncchar; /* synchronization indicator */ 198290001Sglebius char leapchar; /* leap indicator */ 199290001Sglebius char modechar; /* model 320 mode flag */ 200290001Sglebius char siglchar; /* model difference between 33x/325 */ 20182498Sroberto char char_quality[2]; /* temp quality flag */ 20254359Sroberto 20354359Sroberto /* 20454359Sroberto * Initialize pointers and read the timecode and timestamp 20554359Sroberto */ 206290001Sglebius peer = rbufp->recv_peer; 20754359Sroberto pp = peer->procptr; 208290001Sglebius up = pp->unitptr; 20954359Sroberto temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); 21054359Sroberto 21154359Sroberto /* 21254359Sroberto * Note we get a buffer and timestamp for both a <cr> and <lf>, 21382498Sroberto * but only the <cr> timestamp is retained. 21454359Sroberto */ 21554359Sroberto if (temp == 0) { 21654359Sroberto if (up->tcswitch == 0) { 21754359Sroberto up->tcswitch = 1; 21854359Sroberto up->laststamp = trtmp; 21954359Sroberto } else 22054359Sroberto up->tcswitch = 0; 22154359Sroberto return; 22254359Sroberto } 22354359Sroberto pp->lencode = temp; 22454359Sroberto pp->lastrec = up->laststamp; 22554359Sroberto up->laststamp = trtmp; 22654359Sroberto up->tcswitch = 1; 22754359Sroberto#ifdef DEBUG 22854359Sroberto if (debug) 22954359Sroberto printf("ulink: timecode %d %s\n", pp->lencode, 23054359Sroberto pp->a_lastcode); 23154359Sroberto#endif 23254359Sroberto 23354359Sroberto /* 23454359Sroberto * We get down to business, check the timecode format and decode 23582498Sroberto * its contents. If the timecode has invalid length or is not in 23682498Sroberto * proper format, we declare bad format and exit. 23754359Sroberto */ 238182007Sroberto syncchar = leapchar = modechar = siglchar = ' '; 23982498Sroberto switch (pp->lencode ) { 24082498Sroberto case LEN33X: 241182007Sroberto 24282498Sroberto /* 243182007Sroberto * First we check if the format is 33x or 325: 244182007Sroberto * <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5 (33x) 245182007Sroberto * <CR><LF>R5_1C00LYYYY+DDDUTCS HH:MM:SSL+5 (325) 246182007Sroberto * simply by comparing if the signal level is 'S' or 'R' 247182007Sroberto */ 24882498Sroberto 249182007Sroberto if (sscanf(pp->a_lastcode, "%c%*31c", 250182007Sroberto &siglchar) == 1) { 251182007Sroberto 252182007Sroberto if(siglchar == SIGLCHAR325) { 253182007Sroberto 254182007Sroberto /* 255182007Sroberto * decode for a Model 325 decoder. 256182007Sroberto * Timecode format from January 23, 2004 datasheet is: 257182007Sroberto * 258182007Sroberto * <CR><LF>R5_1C00LYYYY+DDDUTCS HH:MM:SSL+5 259182007Sroberto * 260182007Sroberto * R WWVB decodersignal readability R1 - R5 261182007Sroberto * 5 R1 is unreadable, R5 is best 262182007Sroberto * space a space (0x20) 263182007Sroberto * 1 Data bit 0, 1, M (pos mark), or ? (unknown). 264182007Sroberto * C Reception from either (C)olorado or (H)awaii 265182007Sroberto * 00 Hours since last good WWVB frame sync. Will 266182007Sroberto * be 00-99 267182007Sroberto * space Space char (0x20) or (0xa5) if locked to wwvb 268182007Sroberto * YYYY Current year, 2000-2099 269182007Sroberto * + Leap year indicator. '+' if a leap year, 270182007Sroberto * a space (0x20) if not. 271182007Sroberto * DDD Day of year, 000 - 365. 272182007Sroberto * UTC Timezone (always 'UTC'). 273182007Sroberto * S Daylight savings indicator 274182007Sroberto * S - standard time (STD) in effect 275182007Sroberto * O - during STD to DST day 0000-2400 276182007Sroberto * D - daylight savings time (DST) in effect 277182007Sroberto * I - during DST to STD day 0000-2400 278182007Sroberto * space Space character (0x20) 279182007Sroberto * HH Hours 00-23 280182007Sroberto * : This is the REAL in sync indicator (: = insync) 281182007Sroberto * MM Minutes 00-59 282182007Sroberto * : : = in sync ? = NOT in sync 283182007Sroberto * SS Seconds 00-59 284182007Sroberto * L Leap second flag. Changes from space (0x20) 285182007Sroberto * to 'I' or 'D' during month preceding leap 286182007Sroberto * second adjustment. (I)nsert or (D)elete 287182007Sroberto * +5 UT1 correction (sign + digit )) 288182007Sroberto */ 289182007Sroberto 290182007Sroberto if (sscanf(pp->a_lastcode, 291182007Sroberto "%*2c %*2c%2c%*c%4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c", 292182007Sroberto char_quality, &pp->year, &pp->day, 293182007Sroberto &pp->hour, &syncchar, &pp->minute, &pp->second, 294182007Sroberto &leapchar) == 8) { 295182007Sroberto 296182007Sroberto if (char_quality[0] == '0') { 297182007Sroberto quality = 0; 298182007Sroberto } else if (char_quality[0] == '0') { 299182007Sroberto quality = (char_quality[1] & 0x0f); 300182007Sroberto } else { 301182007Sroberto quality = 99; 302182007Sroberto } 303182007Sroberto 304182007Sroberto if (leapchar == 'I' ) leapchar = '+'; 305182007Sroberto if (leapchar == 'D' ) leapchar = '-'; 306182007Sroberto 307182007Sroberto /* 308182007Sroberto #ifdef DEBUG 309182007Sroberto if (debug) { 310182007Sroberto printf("ulink: char_quality %c %c\n", 311182007Sroberto char_quality[0], char_quality[1]); 312182007Sroberto printf("ulink: quality %d\n", quality); 313182007Sroberto printf("ulink: syncchar %x\n", syncchar); 314182007Sroberto printf("ulink: leapchar %x\n", leapchar); 315182007Sroberto } 316182007Sroberto #endif 317182007Sroberto */ 318182007Sroberto 319182007Sroberto } 32082498Sroberto 321182007Sroberto } 322182007Sroberto if(siglchar == SIGLCHAR33x) { 323182007Sroberto 324182007Sroberto /* 325182007Sroberto * We got a Model 33X decoder. 326182007Sroberto * Timecode format from January 29, 2001 datasheet is: 327182007Sroberto * <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5 328182007Sroberto * S WWVB decoder sync indicator. S for in-sync(?) 329182007Sroberto * or N for noisy signal. 330182007Sroberto * 9+ RF signal level in S-units, 0-9 followed by 331182007Sroberto * a space (0x20). The space turns to '+' if the 332182007Sroberto * level is over 9. 333182007Sroberto * D Data bit 0, 1, 2 (position mark), or 334182007Sroberto * 3 (unknown). 335182007Sroberto * space Space character (0x20) 336182007Sroberto * 00 Hours since last good WWVB frame sync. Will 337182007Sroberto * be 00-23 hrs, or '1d' to '7d'. Will be 'Lk' 338182007Sroberto * if currently in sync. 339182007Sroberto * space Space character (0x20) 340182007Sroberto * YYYY Current year, 1990-2089 341182007Sroberto * + Leap year indicator. '+' if a leap year, 342182007Sroberto * a space (0x20) if not. 343182007Sroberto * DDD Day of year, 001 - 366. 344182007Sroberto * UTC Timezone (always 'UTC'). 345182007Sroberto * S Daylight savings indicator 346182007Sroberto * S - standard time (STD) in effect 347182007Sroberto * O - during STD to DST day 0000-2400 348182007Sroberto * D - daylight savings time (DST) in effect 349182007Sroberto * I - during DST to STD day 0000-2400 350182007Sroberto * space Space character (0x20) 351182007Sroberto * HH Hours 00-23 352182007Sroberto * : This is the REAL in sync indicator (: = insync) 353182007Sroberto * MM Minutes 00-59 354182007Sroberto * : : = in sync ? = NOT in sync 355182007Sroberto * SS Seconds 00-59 356182007Sroberto * L Leap second flag. Changes from space (0x20) 357182007Sroberto * to '+' or '-' during month preceding leap 358182007Sroberto * second adjustment. 359182007Sroberto * +5 UT1 correction (sign + digit )) 360182007Sroberto */ 361182007Sroberto 362182007Sroberto if (sscanf(pp->a_lastcode, 363182007Sroberto "%*4c %2c %4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c", 364182007Sroberto char_quality, &pp->year, &pp->day, 365182007Sroberto &pp->hour, &syncchar, &pp->minute, &pp->second, 366182007Sroberto &leapchar) == 8) { 367182007Sroberto 368182007Sroberto if (char_quality[0] == 'L') { 36982498Sroberto quality = 0; 370182007Sroberto } else if (char_quality[0] == '0') { 37182498Sroberto quality = (char_quality[1] & 0x0f); 372182007Sroberto } else { 37382498Sroberto quality = 99; 374182007Sroberto } 37554359Sroberto 376182007Sroberto /* 377182007Sroberto #ifdef DEBUG 378182007Sroberto if (debug) { 379182007Sroberto printf("ulink: char_quality %c %c\n", 380182007Sroberto char_quality[0], char_quality[1]); 381182007Sroberto printf("ulink: quality %d\n", quality); 382182007Sroberto printf("ulink: syncchar %x\n", syncchar); 383182007Sroberto printf("ulink: leapchar %x\n", leapchar); 384182007Sroberto } 385182007Sroberto #endif 386182007Sroberto */ 38782498Sroberto 388182007Sroberto } 389182007Sroberto } 390182007Sroberto break; 39182498Sroberto } 392182007Sroberto 39382498Sroberto case LEN320: 394182007Sroberto 39582498Sroberto /* 39682498Sroberto * Model 320 Decoder 39782498Sroberto * The timecode format is: 39882498Sroberto * 39982498Sroberto * <cr><lf>SQRYYYYDDD+HH:MM:SS.mmLT<cr> 40082498Sroberto * 40182498Sroberto * where: 40282498Sroberto * 40382498Sroberto * S = 'S' -- sync'd in last hour, 40482498Sroberto * '0'-'9' - hours x 10 since last update, 40582498Sroberto * '?' -- not in sync 40682498Sroberto * Q = Number of correlating time-frames, from 0 to 5 40782498Sroberto * R = 'R' -- reception in progress, 40882498Sroberto * 'N' -- Noisy reception, 40982498Sroberto * ' ' -- standby mode 41082498Sroberto * YYYY = year from 1990 to 2089 41182498Sroberto * DDD = current day from 1 to 366 41282498Sroberto * + = '+' if current year is a leap year, else ' ' 41382498Sroberto * HH = UTC hour 0 to 23 41482498Sroberto * MM = Minutes of current hour from 0 to 59 41582498Sroberto * SS = Seconds of current minute from 0 to 59 41682498Sroberto * mm = 10's milliseconds of the current second from 00 to 99 41782498Sroberto * L = Leap second pending at end of month 41882498Sroberto * 'I' = insert, 'D'= delete 41982498Sroberto * T = DST <-> STD transition indicators 42082498Sroberto * 42182498Sroberto */ 422182007Sroberto 423132451Sroberto if (sscanf(pp->a_lastcode, "%c%1d%c%4d%3d%*c%2d:%2d:%2d.%2ld%c", 42482498Sroberto &syncchar, &quality, &modechar, &pp->year, &pp->day, 42582498Sroberto &pp->hour, &pp->minute, &pp->second, 426132451Sroberto &pp->nsec, &leapchar) == 10) { 427132451Sroberto pp->nsec *= 10000000; /* M320 returns 10's of msecs */ 42882498Sroberto if (leapchar == 'I' ) leapchar = '+'; 42982498Sroberto if (leapchar == 'D' ) leapchar = '-'; 43082498Sroberto if (syncchar != '?' ) syncchar = ':'; 43182498Sroberto 43282498Sroberto break; 43382498Sroberto } 43482498Sroberto 43582498Sroberto default: 43682498Sroberto refclock_report(peer, CEVNT_BADREPLY); 43782498Sroberto return; 43882498Sroberto } 43982498Sroberto 44054359Sroberto /* 44182498Sroberto * Decode quality indicator 44282498Sroberto * For the 325 & 33x series, the lower the number the "better" 44382498Sroberto * the time is. I used the dispersion as the measure of time 44482498Sroberto * quality. The quality indicator in the 320 is the number of 44582498Sroberto * correlating time frames (the more the better) 44654359Sroberto */ 44754359Sroberto 44882498Sroberto /* 44982498Sroberto * The spec sheet for the 325 & 33x series states the clock will 45082498Sroberto * maintain +/-0.002 seconds accuracy when locked to WWVB. This 45182498Sroberto * is indicated by 'Lk' in the quality portion of the incoming 45282498Sroberto * string. When not in lock, a drift of +/-0.015 seconds should 45382498Sroberto * be allowed for. 45482498Sroberto * With the quality indicator decoding scheme above, the 'Lk' 45582498Sroberto * condition will produce a quality value of 0. If the quality 45682498Sroberto * indicator starts with '0' then the second character is the 45782498Sroberto * number of hours since we were last locked. If the first 45882498Sroberto * character is anything other than 'L' or '0' then we have been 45982498Sroberto * out of lock for more than 9 hours so we assume the worst and 46082498Sroberto * force a quality value that selects the 'default' maximum 46182498Sroberto * dispersion. The dispersion values below are what came with the 46282498Sroberto * driver. They're not unreasonable so they've not been changed. 46382498Sroberto */ 46454359Sroberto 46582498Sroberto if (pp->lencode == LEN33X) { 46682498Sroberto switch (quality) { 46782498Sroberto case 0 : 46882498Sroberto pp->disp=.002; 46982498Sroberto break; 47082498Sroberto case 1 : 47182498Sroberto pp->disp=.02; 47282498Sroberto break; 47382498Sroberto case 2 : 47482498Sroberto pp->disp=.04; 47582498Sroberto break; 47682498Sroberto case 3 : 47782498Sroberto pp->disp=.08; 47882498Sroberto break; 47982498Sroberto default: 48082498Sroberto pp->disp=MAXDISPERSE; 48182498Sroberto break; 48282498Sroberto } 48382498Sroberto } else { 48482498Sroberto switch (quality) { 48582498Sroberto case 5 : 48682498Sroberto pp->disp=.002; 48782498Sroberto break; 48882498Sroberto case 4 : 48982498Sroberto pp->disp=.02; 49082498Sroberto break; 49182498Sroberto case 3 : 49282498Sroberto pp->disp=.04; 49382498Sroberto break; 49482498Sroberto case 2 : 49582498Sroberto pp->disp=.08; 49682498Sroberto break; 49782498Sroberto case 1 : 49882498Sroberto pp->disp=.16; 49982498Sroberto break; 50082498Sroberto default: 50182498Sroberto pp->disp=MAXDISPERSE; 50282498Sroberto break; 50382498Sroberto } 50482498Sroberto 50582498Sroberto } 50682498Sroberto 50754359Sroberto /* 50882498Sroberto * Decode synchronization, and leap characters. If 50954359Sroberto * unsynchronized, set the leap bits accordingly and exit. 51054359Sroberto * Otherwise, set the leap bits according to the leap character. 51154359Sroberto */ 51254359Sroberto 51382498Sroberto if (syncchar != ':') 51482498Sroberto pp->leap = LEAP_NOTINSYNC; 51582498Sroberto else if (leapchar == '+') 51682498Sroberto pp->leap = LEAP_ADDSECOND; 51782498Sroberto else if (leapchar == '-') 51882498Sroberto pp->leap = LEAP_DELSECOND; 51982498Sroberto else 52082498Sroberto pp->leap = LEAP_NOWARNING; 52182498Sroberto 52254359Sroberto /* 52354359Sroberto * Process the new sample in the median filter and determine the 52454359Sroberto * timecode timestamp. 52554359Sroberto */ 52682498Sroberto if (!refclock_process(pp)) { 52754359Sroberto refclock_report(peer, CEVNT_BADTIME); 52882498Sroberto } 52982498Sroberto 53054359Sroberto} 53154359Sroberto 53254359Sroberto/* 53354359Sroberto * ulink_poll - called by the transmit procedure 53454359Sroberto */ 535182007Sroberto 53654359Srobertostatic void 53754359Srobertoulink_poll( 53854359Sroberto int unit, 53954359Sroberto struct peer *peer 54054359Sroberto ) 54154359Sroberto{ 54282498Sroberto struct refclockproc *pp; 54382498Sroberto char pollchar; 54454359Sroberto 54582498Sroberto pp = peer->procptr; 54682498Sroberto pollchar = 'T'; 54782498Sroberto if (pp->sloppyclockflag & CLK_FLAG1) { 54882498Sroberto if (write(pp->io.fd, &pollchar, 1) != 1) 54982498Sroberto refclock_report(peer, CEVNT_FAULT); 55082498Sroberto else 55182498Sroberto pp->polls++; 55282498Sroberto } 55354359Sroberto else 55482498Sroberto pp->polls++; 55554359Sroberto 55682498Sroberto if (pp->coderecv == pp->codeproc) { 55782498Sroberto refclock_report(peer, CEVNT_TIMEOUT); 55882498Sroberto return; 55982498Sroberto } 560132451Sroberto pp->lastref = pp->lastrec; 561132451Sroberto refclock_receive(peer); 562132451Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 56382498Sroberto 56454359Sroberto} 56554359Sroberto 56654359Sroberto#else 56754359Srobertoint refclock_ulink_bs; 56854359Sroberto#endif /* REFCLOCK */ 569