1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite 3c0b746e5SOllivier Robert * Controlled Clock 4c0b746e5SOllivier Robert */ 5c0b746e5SOllivier Robert 6c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 7c0b746e5SOllivier Robert #include <config.h> 8c0b746e5SOllivier Robert #endif 9c0b746e5SOllivier Robert 10c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_ARBITER) 11c0b746e5SOllivier Robert 12c0b746e5SOllivier Robert #include "ntpd.h" 13c0b746e5SOllivier Robert #include "ntp_io.h" 14c0b746e5SOllivier Robert #include "ntp_refclock.h" 15c0b746e5SOllivier Robert #include "ntp_stdlib.h" 16c0b746e5SOllivier Robert 17224ba2bdSOllivier Robert #include <stdio.h> 18224ba2bdSOllivier Robert #include <ctype.h> 19224ba2bdSOllivier Robert 20c0b746e5SOllivier Robert /* 21c0b746e5SOllivier Robert * This driver supports the Arbiter 1088A/B Satellite Controlled Clock. 22c0b746e5SOllivier Robert * The claimed accuracy of this clock is 100 ns relative to the PPS 23c0b746e5SOllivier Robert * output when receiving four or more satellites. 24c0b746e5SOllivier Robert * 25c0b746e5SOllivier Robert * The receiver should be configured before starting the NTP daemon, in 26c0b746e5SOllivier Robert * order to establish reliable position and operating conditions. It 27c0b746e5SOllivier Robert * does not initiate surveying or hold mode. For use with NTP, the 28c0b746e5SOllivier Robert * daylight savings time feature should be disables (D0 command) and the 29c0b746e5SOllivier Robert * broadcast mode set to operate in UTC (BU command). 30c0b746e5SOllivier Robert * 31c0b746e5SOllivier Robert * The timecode format supported by this driver is selected by the poll 32c0b746e5SOllivier Robert * sequence "B5", which initiates a line in the following format to be 33c0b746e5SOllivier Robert * repeated once per second until turned off by the "B0" poll sequence. 34c0b746e5SOllivier Robert * 35c0b746e5SOllivier Robert * Format B5 (24 ASCII printing characters): 36c0b746e5SOllivier Robert * 37c0b746e5SOllivier Robert * <cr><lf>i yy ddd hh:mm:ss.000bbb 38c0b746e5SOllivier Robert * 39c0b746e5SOllivier Robert * on-time = <cr> 40c0b746e5SOllivier Robert * i = synchronization flag (' ' = locked, '?' = unlocked) 41c0b746e5SOllivier Robert * yy = year of century 42c0b746e5SOllivier Robert * ddd = day of year 43c0b746e5SOllivier Robert * hh:mm:ss = hours, minutes, seconds 44c0b746e5SOllivier Robert * .000 = fraction of second (not used) 45c0b746e5SOllivier Robert * bbb = tailing spaces for fill 46c0b746e5SOllivier Robert * 47c0b746e5SOllivier Robert * The alarm condition is indicated by a '?' at i, which indicates the 48c0b746e5SOllivier Robert * receiver is not synchronized. In normal operation, a line consisting 49c0b746e5SOllivier Robert * of the timecode followed by the time quality character (TQ) followed 50c0b746e5SOllivier Robert * by the receiver status string (SR) is written to the clockstats file. 51c0b746e5SOllivier Robert * The time quality character is encoded in IEEE P1344 standard: 52c0b746e5SOllivier Robert * 53c0b746e5SOllivier Robert * Format TQ (IEEE P1344 estimated worst-case time quality) 54c0b746e5SOllivier Robert * 55c0b746e5SOllivier Robert * 0 clock locked, maximum accuracy 56c0b746e5SOllivier Robert * F clock failure, time not reliable 57c0b746e5SOllivier Robert * 4 clock unlocked, accuracy < 1 us 58c0b746e5SOllivier Robert * 5 clock unlocked, accuracy < 10 us 59c0b746e5SOllivier Robert * 6 clock unlocked, accuracy < 100 us 60c0b746e5SOllivier Robert * 7 clock unlocked, accuracy < 1 ms 61c0b746e5SOllivier Robert * 8 clock unlocked, accuracy < 10 ms 62c0b746e5SOllivier Robert * 9 clock unlocked, accuracy < 100 ms 63c0b746e5SOllivier Robert * A clock unlocked, accuracy < 1 s 64c0b746e5SOllivier Robert * B clock unlocked, accuracy < 10 s 65c0b746e5SOllivier Robert * 66c0b746e5SOllivier Robert * The status string is encoded as follows: 67c0b746e5SOllivier Robert * 68c0b746e5SOllivier Robert * Format SR (25 ASCII printing characters) 69c0b746e5SOllivier Robert * 70c0b746e5SOllivier Robert * V=vv S=ss T=t P=pdop E=ee 71c0b746e5SOllivier Robert * 72c0b746e5SOllivier Robert * vv = satellites visible 73c0b746e5SOllivier Robert * ss = relative signal strength 74c0b746e5SOllivier Robert * t = satellites tracked 75c0b746e5SOllivier Robert * pdop = position dilution of precision (meters) 76c0b746e5SOllivier Robert * ee = hardware errors 77c0b746e5SOllivier Robert * 78c0b746e5SOllivier Robert * If flag4 is set, an additional line consisting of the receiver 79ea906c41SOllivier Robert * latitude (LA), longitude (LO), elevation (LH) (meters), and data 80ea906c41SOllivier Robert * buffer (DB) is written to this file. If channel B is enabled for 81ea906c41SOllivier Robert * deviation mode and connected to a 1-PPS signal, the last two numbers 82ea906c41SOllivier Robert * on the line are the deviation and standard deviation averaged over 83ea906c41SOllivier Robert * the last 15 seconds. 84ea906c41SOllivier Robert * 85ea906c41SOllivier Robert * PPS calibration fudge time1 .001240 86c0b746e5SOllivier Robert */ 87c0b746e5SOllivier Robert 88c0b746e5SOllivier Robert /* 89c0b746e5SOllivier Robert * Interface definitions 90c0b746e5SOllivier Robert */ 91c0b746e5SOllivier Robert #define DEVICE "/dev/gps%d" /* device name and unit */ 92c0b746e5SOllivier Robert #define SPEED232 B9600 /* uart speed (9600 baud) */ 93c0b746e5SOllivier Robert #define PRECISION (-20) /* precision assumed (about 1 us) */ 94c0b746e5SOllivier Robert #define REFID "GPS " /* reference ID */ 95c0b746e5SOllivier Robert #define DESCRIPTION "Arbiter 1088A/B GPS Receiver" /* WRU */ 96c0b746e5SOllivier Robert #define LENARB 24 /* format B5 timecode length */ 97ea906c41SOllivier Robert #define MAXSTA 40 /* max length of status string */ 98ea906c41SOllivier Robert #define MAXPOS 80 /* max length of position string */ 99c0b746e5SOllivier Robert 1002b15cb3dSCy Schubert #ifdef PRE_NTP420 1012b15cb3dSCy Schubert #define MODE ttlmax 1022b15cb3dSCy Schubert #else 1032b15cb3dSCy Schubert #define MODE ttl 1042b15cb3dSCy Schubert #endif 1052b15cb3dSCy Schubert 1062b15cb3dSCy Schubert #define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" ) 1072b15cb3dSCy Schubert #define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" ) 1082b15cb3dSCy Schubert 109c0b746e5SOllivier Robert /* 110c0b746e5SOllivier Robert * ARB unit control structure 111c0b746e5SOllivier Robert */ 112c0b746e5SOllivier Robert struct arbunit { 113c0b746e5SOllivier Robert l_fp laststamp; /* last receive timestamp */ 114c0b746e5SOllivier Robert int tcswitch; /* timecode switch/counter */ 115c0b746e5SOllivier Robert char qualchar; /* IEEE P1344 quality (TQ command) */ 116c0b746e5SOllivier Robert char status[MAXSTA]; /* receiver status (SR command) */ 117c0b746e5SOllivier Robert char latlon[MAXPOS]; /* receiver position (lat/lon/alt) */ 118c0b746e5SOllivier Robert }; 119c0b746e5SOllivier Robert 120c0b746e5SOllivier Robert /* 121c0b746e5SOllivier Robert * Function prototypes 122c0b746e5SOllivier Robert */ 1232b15cb3dSCy Schubert static int arb_start (int, struct peer *); 1242b15cb3dSCy Schubert static void arb_shutdown (int, struct peer *); 1252b15cb3dSCy Schubert static void arb_receive (struct recvbuf *); 1262b15cb3dSCy Schubert static void arb_poll (int, struct peer *); 127c0b746e5SOllivier Robert 128c0b746e5SOllivier Robert /* 129c0b746e5SOllivier Robert * Transfer vector 130c0b746e5SOllivier Robert */ 131c0b746e5SOllivier Robert struct refclock refclock_arbiter = { 132c0b746e5SOllivier Robert arb_start, /* start up driver */ 133c0b746e5SOllivier Robert arb_shutdown, /* shut down driver */ 134c0b746e5SOllivier Robert arb_poll, /* transmit poll message */ 135c0b746e5SOllivier Robert noentry, /* not used (old arb_control) */ 136c0b746e5SOllivier Robert noentry, /* initialize driver (not used) */ 137c0b746e5SOllivier Robert noentry, /* not used (old arb_buginfo) */ 138c0b746e5SOllivier Robert NOFLAGS /* not used */ 139c0b746e5SOllivier Robert }; 140c0b746e5SOllivier Robert 141c0b746e5SOllivier Robert 142c0b746e5SOllivier Robert /* 143c0b746e5SOllivier Robert * arb_start - open the devices and initialize data for processing 144c0b746e5SOllivier Robert */ 145c0b746e5SOllivier Robert static int 146c0b746e5SOllivier Robert arb_start( 147c0b746e5SOllivier Robert int unit, 148c0b746e5SOllivier Robert struct peer *peer 149c0b746e5SOllivier Robert ) 150c0b746e5SOllivier Robert { 151c0b746e5SOllivier Robert register struct arbunit *up; 152c0b746e5SOllivier Robert struct refclockproc *pp; 153c0b746e5SOllivier Robert int fd; 154c0b746e5SOllivier Robert char device[20]; 155c0b746e5SOllivier Robert 156c0b746e5SOllivier Robert /* 157c0b746e5SOllivier Robert * Open serial port. Use CLK line discipline, if available. 158c0b746e5SOllivier Robert */ 1592b15cb3dSCy Schubert snprintf(device, sizeof(device), DEVICE, unit); 160a466cc55SCy Schubert fd = refclock_open(&peer->srcadr, device, SPEED232, LDISC_CLK); 1612b15cb3dSCy Schubert if (fd <= 0) 162c0b746e5SOllivier Robert return (0); 163c0b746e5SOllivier Robert 164c0b746e5SOllivier Robert /* 165c0b746e5SOllivier Robert * Allocate and initialize unit structure 166c0b746e5SOllivier Robert */ 1672b15cb3dSCy Schubert up = emalloc_zero(sizeof(*up)); 168c0b746e5SOllivier Robert pp = peer->procptr; 169c0b746e5SOllivier Robert pp->io.clock_recv = arb_receive; 1702b15cb3dSCy Schubert pp->io.srcclock = peer; 171c0b746e5SOllivier Robert pp->io.datalen = 0; 172c0b746e5SOllivier Robert pp->io.fd = fd; 173c0b746e5SOllivier Robert if (!io_addclock(&pp->io)) { 1742b15cb3dSCy Schubert close(fd); 1752b15cb3dSCy Schubert pp->io.fd = -1; 176c0b746e5SOllivier Robert free(up); 177c0b746e5SOllivier Robert return (0); 178c0b746e5SOllivier Robert } 1792b15cb3dSCy Schubert pp->unitptr = up; 180c0b746e5SOllivier Robert 181c0b746e5SOllivier Robert /* 182c0b746e5SOllivier Robert * Initialize miscellaneous variables 183c0b746e5SOllivier Robert */ 184c0b746e5SOllivier Robert peer->precision = PRECISION; 185c0b746e5SOllivier Robert pp->clockdesc = DESCRIPTION; 186c0b746e5SOllivier Robert memcpy((char *)&pp->refid, REFID, 4); 1872b15cb3dSCy Schubert if (peer->MODE > 1) { 1882b15cb3dSCy Schubert msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE); 1892b15cb3dSCy Schubert close(fd); 1902b15cb3dSCy Schubert pp->io.fd = -1; 1912b15cb3dSCy Schubert free(up); 1922b15cb3dSCy Schubert return (0); 1932b15cb3dSCy Schubert } 1942b15cb3dSCy Schubert #ifdef DEBUG 1952b15cb3dSCy Schubert if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); } 1962b15cb3dSCy Schubert #endif 197a466cc55SCy Schubert refclock_write(peer, COMMAND_HALT_BCAST, 2, "HALT_BCAST"); 198c0b746e5SOllivier Robert return (1); 199c0b746e5SOllivier Robert } 200c0b746e5SOllivier Robert 201c0b746e5SOllivier Robert 202c0b746e5SOllivier Robert /* 203c0b746e5SOllivier Robert * arb_shutdown - shut down the clock 204c0b746e5SOllivier Robert */ 205c0b746e5SOllivier Robert static void 206c0b746e5SOllivier Robert arb_shutdown( 207c0b746e5SOllivier Robert int unit, 208c0b746e5SOllivier Robert struct peer *peer 209c0b746e5SOllivier Robert ) 210c0b746e5SOllivier Robert { 211c0b746e5SOllivier Robert register struct arbunit *up; 212c0b746e5SOllivier Robert struct refclockproc *pp; 213c0b746e5SOllivier Robert 214c0b746e5SOllivier Robert pp = peer->procptr; 2152b15cb3dSCy Schubert up = pp->unitptr; 2162b15cb3dSCy Schubert if (-1 != pp->io.fd) 217c0b746e5SOllivier Robert io_closeclock(&pp->io); 2182b15cb3dSCy Schubert if (NULL != up) 219c0b746e5SOllivier Robert free(up); 220c0b746e5SOllivier Robert } 221c0b746e5SOllivier Robert 222c0b746e5SOllivier Robert 223c0b746e5SOllivier Robert /* 224c0b746e5SOllivier Robert * arb_receive - receive data from the serial interface 225c0b746e5SOllivier Robert */ 226c0b746e5SOllivier Robert static void 227c0b746e5SOllivier Robert arb_receive( 228c0b746e5SOllivier Robert struct recvbuf *rbufp 229c0b746e5SOllivier Robert ) 230c0b746e5SOllivier Robert { 231c0b746e5SOllivier Robert register struct arbunit *up; 232c0b746e5SOllivier Robert struct refclockproc *pp; 233c0b746e5SOllivier Robert struct peer *peer; 234c0b746e5SOllivier Robert l_fp trtmp; 235c0b746e5SOllivier Robert int temp; 236ea906c41SOllivier Robert u_char syncchar; /* synch indicator */ 237ea906c41SOllivier Robert char tbuf[BMAX]; /* temp buffer */ 238c0b746e5SOllivier Robert 239c0b746e5SOllivier Robert /* 240c0b746e5SOllivier Robert * Initialize pointers and read the timecode and timestamp 241c0b746e5SOllivier Robert */ 2422b15cb3dSCy Schubert peer = rbufp->recv_peer; 243c0b746e5SOllivier Robert pp = peer->procptr; 2442b15cb3dSCy Schubert up = pp->unitptr; 2452b15cb3dSCy Schubert temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp); 246c0b746e5SOllivier Robert 247c0b746e5SOllivier Robert /* 248c0b746e5SOllivier Robert * Note we get a buffer and timestamp for both a <cr> and <lf>, 249c0b746e5SOllivier Robert * but only the <cr> timestamp is retained. The program first 250c0b746e5SOllivier Robert * sends a TQ and expects the echo followed by the time quality 251c0b746e5SOllivier Robert * character. It then sends a B5 starting the timecode broadcast 252c0b746e5SOllivier Robert * and expects the echo followed some time later by the on-time 253c0b746e5SOllivier Robert * character <cr> and then the <lf> beginning the timecode 254c0b746e5SOllivier Robert * itself. Finally, at the <cr> beginning the next timecode at 255c0b746e5SOllivier Robert * the next second, the program sends a B0 shutting down the 256c0b746e5SOllivier Robert * timecode broadcast. 257c0b746e5SOllivier Robert * 258c0b746e5SOllivier Robert * If flag4 is set, the program snatches the latitude, longitude 259c0b746e5SOllivier Robert * and elevation and writes it to the clockstats file. 260c0b746e5SOllivier Robert */ 261c0b746e5SOllivier Robert if (temp == 0) 262c0b746e5SOllivier Robert return; 263ea906c41SOllivier Robert 264c0b746e5SOllivier Robert pp->lastrec = up->laststamp; 265c0b746e5SOllivier Robert up->laststamp = trtmp; 266c0b746e5SOllivier Robert if (temp < 3) 267c0b746e5SOllivier Robert return; 268ea906c41SOllivier Robert 269c0b746e5SOllivier Robert if (up->tcswitch == 0) { 270c0b746e5SOllivier Robert 271c0b746e5SOllivier Robert /* 272c0b746e5SOllivier Robert * Collect statistics. If nothing is recogized, just 273c0b746e5SOllivier Robert * ignore; sometimes the clock doesn't stop spewing 274ea906c41SOllivier Robert * timecodes for awhile after the B0 command. 275ea906c41SOllivier Robert * 276ea906c41SOllivier Robert * If flag4 is not set, send TQ, SR, B5. If flag4 is 277ea906c41SOllivier Robert * sset, send TQ, SR, LA, LO, LH, DB, B5. When the 278ea906c41SOllivier Robert * median filter is full, send B0. 279c0b746e5SOllivier Robert */ 280ea906c41SOllivier Robert if (!strncmp(tbuf, "TQ", 2)) { 281ea906c41SOllivier Robert up->qualchar = tbuf[2]; 282a466cc55SCy Schubert refclock_write(peer, "SR", 2, "SR"); 283ea906c41SOllivier Robert return; 284ea906c41SOllivier Robert 285ea906c41SOllivier Robert } else if (!strncmp(tbuf, "SR", 2)) { 2862b15cb3dSCy Schubert strlcpy(up->status, tbuf + 2, 2872b15cb3dSCy Schubert sizeof(up->status)); 288c0b746e5SOllivier Robert if (pp->sloppyclockflag & CLK_FLAG4) 289a466cc55SCy Schubert refclock_write(peer, "LA", 2, "LA"); 290ea906c41SOllivier Robert else 291a466cc55SCy Schubert refclock_write(peer, COMMAND_START_BCAST, 2, 292a466cc55SCy Schubert COMMAND_START_BCAST); 293c0b746e5SOllivier Robert return; 294ea906c41SOllivier Robert 295ea906c41SOllivier Robert } else if (!strncmp(tbuf, "LA", 2)) { 2962b15cb3dSCy Schubert strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon)); 297a466cc55SCy Schubert refclock_write(peer, "LO", 2, "LO"); 298ea906c41SOllivier Robert return; 299ea906c41SOllivier Robert 300ea906c41SOllivier Robert } else if (!strncmp(tbuf, "LO", 2)) { 3012b15cb3dSCy Schubert strlcat(up->latlon, " ", sizeof(up->latlon)); 3022b15cb3dSCy Schubert strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); 303a466cc55SCy Schubert refclock_write(peer, "LH", 2, "LH"); 304ea906c41SOllivier Robert return; 305ea906c41SOllivier Robert 306ea906c41SOllivier Robert } else if (!strncmp(tbuf, "LH", 2)) { 3072b15cb3dSCy Schubert strlcat(up->latlon, " ", sizeof(up->latlon)); 3082b15cb3dSCy Schubert strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); 309a466cc55SCy Schubert refclock_write(peer, "DB", 2, "DB"); 310ea906c41SOllivier Robert return; 311ea906c41SOllivier Robert 312ea906c41SOllivier Robert } else if (!strncmp(tbuf, "DB", 2)) { 3132b15cb3dSCy Schubert strlcat(up->latlon, " ", sizeof(up->latlon)); 3142b15cb3dSCy Schubert strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); 315ea906c41SOllivier Robert record_clock_stats(&peer->srcadr, up->latlon); 316ea906c41SOllivier Robert #ifdef DEBUG 317ea906c41SOllivier Robert if (debug) 318ea906c41SOllivier Robert printf("arbiter: %s\n", up->latlon); 319ea906c41SOllivier Robert #endif 320a466cc55SCy Schubert refclock_write(peer, COMMAND_START_BCAST, 2, 321a466cc55SCy Schubert COMMAND_START_BCAST); 322c0b746e5SOllivier Robert } 323ea906c41SOllivier Robert } 324c0b746e5SOllivier Robert 325c0b746e5SOllivier Robert /* 326c0b746e5SOllivier Robert * We get down to business, check the timecode format and decode 327c0b746e5SOllivier Robert * its contents. If the timecode has valid length, but not in 328c0b746e5SOllivier Robert * proper format, we declare bad format and exit. If the 329c0b746e5SOllivier Robert * timecode has invalid length, which sometimes occurs when the 330c0b746e5SOllivier Robert * B0 amputates the broadcast, we just quietly steal away. Note 331c0b746e5SOllivier Robert * that the time quality character and receiver status string is 332c0b746e5SOllivier Robert * tacked on the end for clockstats display. 333c0b746e5SOllivier Robert */ 334ea906c41SOllivier Robert up->tcswitch++; 335ea906c41SOllivier Robert if (up->tcswitch <= 1 || temp < LENARB) 336ea906c41SOllivier Robert return; 337ea906c41SOllivier Robert 338c0b746e5SOllivier Robert /* 339c0b746e5SOllivier Robert * Timecode format B5: "i yy ddd hh:mm:ss.000 " 340c0b746e5SOllivier Robert */ 3412b15cb3dSCy Schubert strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode)); 342c0b746e5SOllivier Robert pp->a_lastcode[LENARB - 2] = up->qualchar; 3432b15cb3dSCy Schubert strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode)); 344ea906c41SOllivier Robert pp->lencode = strlen(pp->a_lastcode); 345c0b746e5SOllivier Robert syncchar = ' '; 346c0b746e5SOllivier Robert if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d", 347c0b746e5SOllivier Robert &syncchar, &pp->year, &pp->day, &pp->hour, 348c0b746e5SOllivier Robert &pp->minute, &pp->second) != 6) { 349c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 350a466cc55SCy Schubert refclock_write(peer, COMMAND_HALT_BCAST, 2, COMMAND_HALT_BCAST); 351c0b746e5SOllivier Robert return; 352c0b746e5SOllivier Robert } 353c0b746e5SOllivier Robert 354c0b746e5SOllivier Robert /* 355c0b746e5SOllivier Robert * We decode the clock dispersion from the time quality 356c0b746e5SOllivier Robert * character. 357c0b746e5SOllivier Robert */ 358c0b746e5SOllivier Robert switch (up->qualchar) { 359c0b746e5SOllivier Robert 360c0b746e5SOllivier Robert case '0': /* locked, max accuracy */ 361c0b746e5SOllivier Robert pp->disp = 1e-7; 362ea906c41SOllivier Robert pp->lastref = pp->lastrec; 363c0b746e5SOllivier Robert break; 364c0b746e5SOllivier Robert 365c0b746e5SOllivier Robert case '4': /* unlock accuracy < 1 us */ 366c0b746e5SOllivier Robert pp->disp = 1e-6; 367c0b746e5SOllivier Robert break; 368c0b746e5SOllivier Robert 369c0b746e5SOllivier Robert case '5': /* unlock accuracy < 10 us */ 370c0b746e5SOllivier Robert pp->disp = 1e-5; 371c0b746e5SOllivier Robert break; 372c0b746e5SOllivier Robert 373c0b746e5SOllivier Robert case '6': /* unlock accuracy < 100 us */ 374c0b746e5SOllivier Robert pp->disp = 1e-4; 375c0b746e5SOllivier Robert break; 376c0b746e5SOllivier Robert 377c0b746e5SOllivier Robert case '7': /* unlock accuracy < 1 ms */ 378c0b746e5SOllivier Robert pp->disp = .001; 379c0b746e5SOllivier Robert break; 380c0b746e5SOllivier Robert 381c0b746e5SOllivier Robert case '8': /* unlock accuracy < 10 ms */ 382c0b746e5SOllivier Robert pp->disp = .01; 383c0b746e5SOllivier Robert break; 384c0b746e5SOllivier Robert 385c0b746e5SOllivier Robert case '9': /* unlock accuracy < 100 ms */ 386c0b746e5SOllivier Robert pp->disp = .1; 387c0b746e5SOllivier Robert break; 388c0b746e5SOllivier Robert 389c0b746e5SOllivier Robert case 'A': /* unlock accuracy < 1 s */ 390c0b746e5SOllivier Robert pp->disp = 1; 391c0b746e5SOllivier Robert break; 392c0b746e5SOllivier Robert 393c0b746e5SOllivier Robert case 'B': /* unlock accuracy < 10 s */ 394c0b746e5SOllivier Robert pp->disp = 10; 395c0b746e5SOllivier Robert break; 396c0b746e5SOllivier Robert 397c0b746e5SOllivier Robert case 'F': /* clock failure */ 398c0b746e5SOllivier Robert pp->disp = MAXDISPERSE; 399c0b746e5SOllivier Robert refclock_report(peer, CEVNT_FAULT); 400a466cc55SCy Schubert refclock_write(peer, COMMAND_HALT_BCAST, 2, 401a466cc55SCy Schubert COMMAND_HALT_BCAST); 402c0b746e5SOllivier Robert return; 403c0b746e5SOllivier Robert 404c0b746e5SOllivier Robert default: 405c0b746e5SOllivier Robert pp->disp = MAXDISPERSE; 406c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 407a466cc55SCy Schubert refclock_write(peer, COMMAND_HALT_BCAST, 2, 408a466cc55SCy Schubert COMMAND_HALT_BCAST); 409c0b746e5SOllivier Robert return; 410c0b746e5SOllivier Robert } 411c0b746e5SOllivier Robert if (syncchar != ' ') 412c0b746e5SOllivier Robert pp->leap = LEAP_NOTINSYNC; 413c0b746e5SOllivier Robert else 414c0b746e5SOllivier Robert pp->leap = LEAP_NOWARNING; 415c0b746e5SOllivier Robert 416c0b746e5SOllivier Robert /* 417c0b746e5SOllivier Robert * Process the new sample in the median filter and determine the 418c0b746e5SOllivier Robert * timecode timestamp. 419c0b746e5SOllivier Robert */ 420c0b746e5SOllivier Robert if (!refclock_process(pp)) 421c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADTIME); 422ea906c41SOllivier Robert else if (peer->disp > MAXDISTANCE) 423ea906c41SOllivier Robert refclock_receive(peer); 424ea906c41SOllivier Robert 4252b15cb3dSCy Schubert /* if (up->tcswitch >= MAXSTAGE) { */ 426a466cc55SCy Schubert refclock_write(peer, COMMAND_HALT_BCAST, 2, COMMAND_HALT_BCAST); 4272b15cb3dSCy Schubert /* } */ 428c0b746e5SOllivier Robert } 429c0b746e5SOllivier Robert 430c0b746e5SOllivier Robert 431c0b746e5SOllivier Robert /* 432c0b746e5SOllivier Robert * arb_poll - called by the transmit procedure 433c0b746e5SOllivier Robert */ 434c0b746e5SOllivier Robert static void 435c0b746e5SOllivier Robert arb_poll( 436c0b746e5SOllivier Robert int unit, 437c0b746e5SOllivier Robert struct peer *peer 438c0b746e5SOllivier Robert ) 439c0b746e5SOllivier Robert { 440c0b746e5SOllivier Robert register struct arbunit *up; 441c0b746e5SOllivier Robert struct refclockproc *pp; 442c0b746e5SOllivier Robert 443c0b746e5SOllivier Robert /* 444c0b746e5SOllivier Robert * Time to poll the clock. The Arbiter clock responds to a "B5" 445c0b746e5SOllivier Robert * by returning a timecode in the format specified above. 446c0b746e5SOllivier Robert * Transmission occurs once per second, unless turned off by a 447c0b746e5SOllivier Robert * "B0". Note there is no checking on state, since this may not 448c0b746e5SOllivier Robert * be the only customer reading the clock. Only one customer 449ea906c41SOllivier Robert * need poll the clock; all others just listen in. 450c0b746e5SOllivier Robert */ 451c0b746e5SOllivier Robert pp = peer->procptr; 4522b15cb3dSCy Schubert up = pp->unitptr; 453c0b746e5SOllivier Robert pp->polls++; 454ea906c41SOllivier Robert up->tcswitch = 0; 455a466cc55SCy Schubert if (refclock_write(peer, "TQ", 2, "TQ") != 2) 456ea906c41SOllivier Robert refclock_report(peer, CEVNT_FAULT); 457ea906c41SOllivier Robert 458ea906c41SOllivier Robert /* 459ea906c41SOllivier Robert * Process median filter samples. If none received, declare a 460ea906c41SOllivier Robert * timeout and keep going. 461ea906c41SOllivier Robert */ 462c0b746e5SOllivier Robert if (pp->coderecv == pp->codeproc) { 463c0b746e5SOllivier Robert refclock_report(peer, CEVNT_TIMEOUT); 464c0b746e5SOllivier Robert return; 465c0b746e5SOllivier Robert } 466c0b746e5SOllivier Robert refclock_receive(peer); 4679c2daa00SOllivier Robert record_clock_stats(&peer->srcadr, pp->a_lastcode); 468ea906c41SOllivier Robert #ifdef DEBUG 469ea906c41SOllivier Robert if (debug) 470ea906c41SOllivier Robert printf("arbiter: timecode %d %s\n", 471ea906c41SOllivier Robert pp->lencode, pp->a_lastcode); 472ea906c41SOllivier Robert #endif 473c0b746e5SOllivier Robert } 474c0b746e5SOllivier Robert 475c0b746e5SOllivier Robert #else 476*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT 477c0b746e5SOllivier Robert #endif /* REFCLOCK */ 478