154359Sroberto/* 254359Sroberto * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite 354359Sroberto * Controlled Clock 454359Sroberto */ 554359Sroberto 654359Sroberto#ifdef HAVE_CONFIG_H 754359Sroberto#include <config.h> 854359Sroberto#endif 954359Sroberto 1054359Sroberto#if defined(REFCLOCK) && defined(CLOCK_ARBITER) 1154359Sroberto 1254359Sroberto#include "ntpd.h" 1354359Sroberto#include "ntp_io.h" 1454359Sroberto#include "ntp_refclock.h" 1554359Sroberto#include "ntp_stdlib.h" 1654359Sroberto 1782498Sroberto#include <stdio.h> 1882498Sroberto#include <ctype.h> 1982498Sroberto 20285612Sdelphij#ifdef SYS_WINNT 21285612Sdelphijextern int async_write(int, const void *, unsigned int); 22285612Sdelphij#undef write 23285612Sdelphij#define write(fd, data, octets) async_write(fd, data, octets) 24285612Sdelphij#endif 25285612Sdelphij 2654359Sroberto/* 2754359Sroberto * This driver supports the Arbiter 1088A/B Satellite Controlled Clock. 2854359Sroberto * The claimed accuracy of this clock is 100 ns relative to the PPS 2954359Sroberto * output when receiving four or more satellites. 3054359Sroberto * 3154359Sroberto * The receiver should be configured before starting the NTP daemon, in 3254359Sroberto * order to establish reliable position and operating conditions. It 3354359Sroberto * does not initiate surveying or hold mode. For use with NTP, the 3454359Sroberto * daylight savings time feature should be disables (D0 command) and the 3554359Sroberto * broadcast mode set to operate in UTC (BU command). 3654359Sroberto * 3754359Sroberto * The timecode format supported by this driver is selected by the poll 3854359Sroberto * sequence "B5", which initiates a line in the following format to be 3954359Sroberto * repeated once per second until turned off by the "B0" poll sequence. 4054359Sroberto * 4154359Sroberto * Format B5 (24 ASCII printing characters): 4254359Sroberto * 4354359Sroberto * <cr><lf>i yy ddd hh:mm:ss.000bbb 4454359Sroberto * 4554359Sroberto * on-time = <cr> 4654359Sroberto * i = synchronization flag (' ' = locked, '?' = unlocked) 4754359Sroberto * yy = year of century 4854359Sroberto * ddd = day of year 4954359Sroberto * hh:mm:ss = hours, minutes, seconds 5054359Sroberto * .000 = fraction of second (not used) 5154359Sroberto * bbb = tailing spaces for fill 5254359Sroberto * 5354359Sroberto * The alarm condition is indicated by a '?' at i, which indicates the 5454359Sroberto * receiver is not synchronized. In normal operation, a line consisting 5554359Sroberto * of the timecode followed by the time quality character (TQ) followed 5654359Sroberto * by the receiver status string (SR) is written to the clockstats file. 5754359Sroberto * The time quality character is encoded in IEEE P1344 standard: 5854359Sroberto * 5954359Sroberto * Format TQ (IEEE P1344 estimated worst-case time quality) 6054359Sroberto * 6154359Sroberto * 0 clock locked, maximum accuracy 6254359Sroberto * F clock failure, time not reliable 6354359Sroberto * 4 clock unlocked, accuracy < 1 us 6454359Sroberto * 5 clock unlocked, accuracy < 10 us 6554359Sroberto * 6 clock unlocked, accuracy < 100 us 6654359Sroberto * 7 clock unlocked, accuracy < 1 ms 6754359Sroberto * 8 clock unlocked, accuracy < 10 ms 6854359Sroberto * 9 clock unlocked, accuracy < 100 ms 6954359Sroberto * A clock unlocked, accuracy < 1 s 7054359Sroberto * B clock unlocked, accuracy < 10 s 7154359Sroberto * 7254359Sroberto * The status string is encoded as follows: 7354359Sroberto * 7454359Sroberto * Format SR (25 ASCII printing characters) 7554359Sroberto * 7654359Sroberto * V=vv S=ss T=t P=pdop E=ee 7754359Sroberto * 7854359Sroberto * vv = satellites visible 7954359Sroberto * ss = relative signal strength 8054359Sroberto * t = satellites tracked 8154359Sroberto * pdop = position dilution of precision (meters) 8254359Sroberto * ee = hardware errors 8354359Sroberto * 8454359Sroberto * If flag4 is set, an additional line consisting of the receiver 85182007Sroberto * latitude (LA), longitude (LO), elevation (LH) (meters), and data 86182007Sroberto * buffer (DB) is written to this file. If channel B is enabled for 87182007Sroberto * deviation mode and connected to a 1-PPS signal, the last two numbers 88182007Sroberto * on the line are the deviation and standard deviation averaged over 89182007Sroberto * the last 15 seconds. 90182007Sroberto * 91182007Sroberto * PPS calibration fudge time1 .001240 9254359Sroberto */ 9354359Sroberto 9454359Sroberto/* 9554359Sroberto * Interface definitions 9654359Sroberto */ 9754359Sroberto#define DEVICE "/dev/gps%d" /* device name and unit */ 9854359Sroberto#define SPEED232 B9600 /* uart speed (9600 baud) */ 9954359Sroberto#define PRECISION (-20) /* precision assumed (about 1 us) */ 100182007Sroberto#define REFID "GPS " /* reference ID */ 10154359Sroberto#define DESCRIPTION "Arbiter 1088A/B GPS Receiver" /* WRU */ 10254359Sroberto#define LENARB 24 /* format B5 timecode length */ 103182007Sroberto#define MAXSTA 40 /* max length of status string */ 104182007Sroberto#define MAXPOS 80 /* max length of position string */ 10554359Sroberto 106285612Sdelphij#ifdef PRE_NTP420 107285612Sdelphij#define MODE ttlmax 108285612Sdelphij#else 109285612Sdelphij#define MODE ttl 110285612Sdelphij#endif 111285612Sdelphij 112285612Sdelphij#define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" ) 113285612Sdelphij#define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" ) 114285612Sdelphij 11554359Sroberto/* 11654359Sroberto * ARB unit control structure 11754359Sroberto */ 11854359Srobertostruct arbunit { 11954359Sroberto l_fp laststamp; /* last receive timestamp */ 12054359Sroberto int tcswitch; /* timecode switch/counter */ 12154359Sroberto char qualchar; /* IEEE P1344 quality (TQ command) */ 12254359Sroberto char status[MAXSTA]; /* receiver status (SR command) */ 12354359Sroberto char latlon[MAXPOS]; /* receiver position (lat/lon/alt) */ 12454359Sroberto}; 12554359Sroberto 12654359Sroberto/* 12754359Sroberto * Function prototypes 12854359Sroberto */ 129285612Sdelphijstatic int arb_start (int, struct peer *); 130285612Sdelphijstatic void arb_shutdown (int, struct peer *); 131285612Sdelphijstatic void arb_receive (struct recvbuf *); 132285612Sdelphijstatic void arb_poll (int, struct peer *); 13354359Sroberto 13454359Sroberto/* 13554359Sroberto * Transfer vector 13654359Sroberto */ 13754359Srobertostruct refclock refclock_arbiter = { 13854359Sroberto arb_start, /* start up driver */ 13954359Sroberto arb_shutdown, /* shut down driver */ 14054359Sroberto arb_poll, /* transmit poll message */ 14154359Sroberto noentry, /* not used (old arb_control) */ 14254359Sroberto noentry, /* initialize driver (not used) */ 14354359Sroberto noentry, /* not used (old arb_buginfo) */ 14454359Sroberto NOFLAGS /* not used */ 14554359Sroberto}; 14654359Sroberto 14754359Sroberto 14854359Sroberto/* 14954359Sroberto * arb_start - open the devices and initialize data for processing 15054359Sroberto */ 15154359Srobertostatic int 15254359Srobertoarb_start( 15354359Sroberto int unit, 15454359Sroberto struct peer *peer 15554359Sroberto ) 15654359Sroberto{ 15754359Sroberto register struct arbunit *up; 15854359Sroberto struct refclockproc *pp; 15954359Sroberto int fd; 16054359Sroberto char device[20]; 16154359Sroberto 16254359Sroberto /* 16354359Sroberto * Open serial port. Use CLK line discipline, if available. 16454359Sroberto */ 165285612Sdelphij snprintf(device, sizeof(device), DEVICE, unit); 166285612Sdelphij fd = refclock_open(device, SPEED232, LDISC_CLK); 167285612Sdelphij if (fd <= 0) 16854359Sroberto return (0); 16954359Sroberto 17054359Sroberto /* 17154359Sroberto * Allocate and initialize unit structure 17254359Sroberto */ 173285612Sdelphij up = emalloc_zero(sizeof(*up)); 17454359Sroberto pp = peer->procptr; 17554359Sroberto pp->io.clock_recv = arb_receive; 176285612Sdelphij pp->io.srcclock = peer; 17754359Sroberto pp->io.datalen = 0; 17854359Sroberto pp->io.fd = fd; 17954359Sroberto if (!io_addclock(&pp->io)) { 180285612Sdelphij close(fd); 181285612Sdelphij pp->io.fd = -1; 18254359Sroberto free(up); 18354359Sroberto return (0); 18454359Sroberto } 185285612Sdelphij pp->unitptr = up; 18654359Sroberto 18754359Sroberto /* 18854359Sroberto * Initialize miscellaneous variables 18954359Sroberto */ 19054359Sroberto peer->precision = PRECISION; 19154359Sroberto pp->clockdesc = DESCRIPTION; 19254359Sroberto memcpy((char *)&pp->refid, REFID, 4); 193285612Sdelphij if (peer->MODE > 1) { 194285612Sdelphij msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE); 195285612Sdelphij close(fd); 196285612Sdelphij pp->io.fd = -1; 197285612Sdelphij free(up); 198285612Sdelphij return (0); 199285612Sdelphij } 200285612Sdelphij#ifdef DEBUG 201285612Sdelphij if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); } 202285612Sdelphij#endif 203285612Sdelphij write(pp->io.fd, COMMAND_HALT_BCAST, 2); 20454359Sroberto return (1); 20554359Sroberto} 20654359Sroberto 20754359Sroberto 20854359Sroberto/* 20954359Sroberto * arb_shutdown - shut down the clock 21054359Sroberto */ 21154359Srobertostatic void 21254359Srobertoarb_shutdown( 21354359Sroberto int unit, 21454359Sroberto struct peer *peer 21554359Sroberto ) 21654359Sroberto{ 21754359Sroberto register struct arbunit *up; 21854359Sroberto struct refclockproc *pp; 21954359Sroberto 22054359Sroberto pp = peer->procptr; 221285612Sdelphij up = pp->unitptr; 222285612Sdelphij if (-1 != pp->io.fd) 223285612Sdelphij io_closeclock(&pp->io); 224285612Sdelphij if (NULL != up) 225285612Sdelphij free(up); 22654359Sroberto} 22754359Sroberto 22854359Sroberto 22954359Sroberto/* 23054359Sroberto * arb_receive - receive data from the serial interface 23154359Sroberto */ 23254359Srobertostatic void 23354359Srobertoarb_receive( 23454359Sroberto struct recvbuf *rbufp 23554359Sroberto ) 23654359Sroberto{ 23754359Sroberto register struct arbunit *up; 23854359Sroberto struct refclockproc *pp; 23954359Sroberto struct peer *peer; 24054359Sroberto l_fp trtmp; 24154359Sroberto int temp; 242182007Sroberto u_char syncchar; /* synch indicator */ 243182007Sroberto char tbuf[BMAX]; /* temp buffer */ 24454359Sroberto 24554359Sroberto /* 24654359Sroberto * Initialize pointers and read the timecode and timestamp 24754359Sroberto */ 248285612Sdelphij peer = rbufp->recv_peer; 24954359Sroberto pp = peer->procptr; 250285612Sdelphij up = pp->unitptr; 251285612Sdelphij temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp); 25254359Sroberto 25354359Sroberto /* 25454359Sroberto * Note we get a buffer and timestamp for both a <cr> and <lf>, 25554359Sroberto * but only the <cr> timestamp is retained. The program first 25654359Sroberto * sends a TQ and expects the echo followed by the time quality 25754359Sroberto * character. It then sends a B5 starting the timecode broadcast 25854359Sroberto * and expects the echo followed some time later by the on-time 25954359Sroberto * character <cr> and then the <lf> beginning the timecode 26054359Sroberto * itself. Finally, at the <cr> beginning the next timecode at 26154359Sroberto * the next second, the program sends a B0 shutting down the 26254359Sroberto * timecode broadcast. 26354359Sroberto * 26454359Sroberto * If flag4 is set, the program snatches the latitude, longitude 26554359Sroberto * and elevation and writes it to the clockstats file. 26654359Sroberto */ 26754359Sroberto if (temp == 0) 26854359Sroberto return; 269182007Sroberto 27054359Sroberto pp->lastrec = up->laststamp; 27154359Sroberto up->laststamp = trtmp; 27254359Sroberto if (temp < 3) 27354359Sroberto return; 274182007Sroberto 27554359Sroberto if (up->tcswitch == 0) { 27654359Sroberto 27754359Sroberto /* 27854359Sroberto * Collect statistics. If nothing is recogized, just 27954359Sroberto * ignore; sometimes the clock doesn't stop spewing 280182007Sroberto * timecodes for awhile after the B0 command. 281182007Sroberto * 282182007Sroberto * If flag4 is not set, send TQ, SR, B5. If flag4 is 283182007Sroberto * sset, send TQ, SR, LA, LO, LH, DB, B5. When the 284182007Sroberto * median filter is full, send B0. 28554359Sroberto */ 286182007Sroberto if (!strncmp(tbuf, "TQ", 2)) { 287182007Sroberto up->qualchar = tbuf[2]; 28854359Sroberto write(pp->io.fd, "SR", 2); 289182007Sroberto return; 290182007Sroberto 291182007Sroberto } else if (!strncmp(tbuf, "SR", 2)) { 292285612Sdelphij strlcpy(up->status, tbuf + 2, 293285612Sdelphij sizeof(up->status)); 29454359Sroberto if (pp->sloppyclockflag & CLK_FLAG4) 29554359Sroberto write(pp->io.fd, "LA", 2); 296182007Sroberto else 297285612Sdelphij write(pp->io.fd, COMMAND_START_BCAST, 2); 298182007Sroberto return; 299182007Sroberto 300182007Sroberto } else if (!strncmp(tbuf, "LA", 2)) { 301285612Sdelphij strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon)); 30254359Sroberto write(pp->io.fd, "LO", 2); 303182007Sroberto return; 304182007Sroberto 305182007Sroberto } else if (!strncmp(tbuf, "LO", 2)) { 306285612Sdelphij strlcat(up->latlon, " ", sizeof(up->latlon)); 307285612Sdelphij strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); 30854359Sroberto write(pp->io.fd, "LH", 2); 309182007Sroberto return; 310182007Sroberto 311182007Sroberto } else if (!strncmp(tbuf, "LH", 2)) { 312285612Sdelphij strlcat(up->latlon, " ", sizeof(up->latlon)); 313285612Sdelphij strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); 31454359Sroberto write(pp->io.fd, "DB", 2); 315182007Sroberto return; 316182007Sroberto 317182007Sroberto } else if (!strncmp(tbuf, "DB", 2)) { 318285612Sdelphij strlcat(up->latlon, " ", sizeof(up->latlon)); 319285612Sdelphij strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); 32054359Sroberto record_clock_stats(&peer->srcadr, up->latlon); 321182007Sroberto#ifdef DEBUG 322182007Sroberto if (debug) 323182007Sroberto printf("arbiter: %s\n", up->latlon); 324182007Sroberto#endif 325285612Sdelphij write(pp->io.fd, COMMAND_START_BCAST, 2); 32654359Sroberto } 32754359Sroberto } 32854359Sroberto 32954359Sroberto /* 33054359Sroberto * We get down to business, check the timecode format and decode 33154359Sroberto * its contents. If the timecode has valid length, but not in 33254359Sroberto * proper format, we declare bad format and exit. If the 33354359Sroberto * timecode has invalid length, which sometimes occurs when the 33454359Sroberto * B0 amputates the broadcast, we just quietly steal away. Note 33554359Sroberto * that the time quality character and receiver status string is 33654359Sroberto * tacked on the end for clockstats display. 33754359Sroberto */ 338182007Sroberto up->tcswitch++; 339182007Sroberto if (up->tcswitch <= 1 || temp < LENARB) 340182007Sroberto return; 341182007Sroberto 342182007Sroberto /* 343182007Sroberto * Timecode format B5: "i yy ddd hh:mm:ss.000 " 344182007Sroberto */ 345285612Sdelphij strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode)); 346182007Sroberto pp->a_lastcode[LENARB - 2] = up->qualchar; 347285612Sdelphij strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode)); 348182007Sroberto pp->lencode = strlen(pp->a_lastcode); 349182007Sroberto syncchar = ' '; 350182007Sroberto if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d", 351182007Sroberto &syncchar, &pp->year, &pp->day, &pp->hour, 352182007Sroberto &pp->minute, &pp->second) != 6) { 353182007Sroberto refclock_report(peer, CEVNT_BADREPLY); 354285612Sdelphij write(pp->io.fd, COMMAND_HALT_BCAST, 2); 35554359Sroberto return; 35654359Sroberto } 35754359Sroberto 35854359Sroberto /* 35954359Sroberto * We decode the clock dispersion from the time quality 36054359Sroberto * character. 36154359Sroberto */ 36254359Sroberto switch (up->qualchar) { 36354359Sroberto 36454359Sroberto case '0': /* locked, max accuracy */ 36554359Sroberto pp->disp = 1e-7; 366182007Sroberto pp->lastref = pp->lastrec; 36754359Sroberto break; 36854359Sroberto 36954359Sroberto case '4': /* unlock accuracy < 1 us */ 37054359Sroberto pp->disp = 1e-6; 37154359Sroberto break; 37254359Sroberto 37354359Sroberto case '5': /* unlock accuracy < 10 us */ 37454359Sroberto pp->disp = 1e-5; 37554359Sroberto break; 37654359Sroberto 37754359Sroberto case '6': /* unlock accuracy < 100 us */ 37854359Sroberto pp->disp = 1e-4; 37954359Sroberto break; 38054359Sroberto 38154359Sroberto case '7': /* unlock accuracy < 1 ms */ 38254359Sroberto pp->disp = .001; 38354359Sroberto break; 38454359Sroberto 38554359Sroberto case '8': /* unlock accuracy < 10 ms */ 38654359Sroberto pp->disp = .01; 38754359Sroberto break; 38854359Sroberto 38954359Sroberto case '9': /* unlock accuracy < 100 ms */ 39054359Sroberto pp->disp = .1; 39154359Sroberto break; 39254359Sroberto 39354359Sroberto case 'A': /* unlock accuracy < 1 s */ 39454359Sroberto pp->disp = 1; 39554359Sroberto break; 39654359Sroberto 39754359Sroberto case 'B': /* unlock accuracy < 10 s */ 39854359Sroberto pp->disp = 10; 39954359Sroberto break; 40054359Sroberto 40154359Sroberto case 'F': /* clock failure */ 40254359Sroberto pp->disp = MAXDISPERSE; 40354359Sroberto refclock_report(peer, CEVNT_FAULT); 404285612Sdelphij write(pp->io.fd, COMMAND_HALT_BCAST, 2); 40554359Sroberto return; 40654359Sroberto 40754359Sroberto default: 40854359Sroberto pp->disp = MAXDISPERSE; 40954359Sroberto refclock_report(peer, CEVNT_BADREPLY); 410285612Sdelphij write(pp->io.fd, COMMAND_HALT_BCAST, 2); 41154359Sroberto return; 41254359Sroberto } 41354359Sroberto if (syncchar != ' ') 41454359Sroberto pp->leap = LEAP_NOTINSYNC; 41554359Sroberto else 41654359Sroberto pp->leap = LEAP_NOWARNING; 41754359Sroberto 41854359Sroberto /* 41954359Sroberto * Process the new sample in the median filter and determine the 42054359Sroberto * timecode timestamp. 42154359Sroberto */ 42254359Sroberto if (!refclock_process(pp)) 42354359Sroberto refclock_report(peer, CEVNT_BADTIME); 424182007Sroberto else if (peer->disp > MAXDISTANCE) 425182007Sroberto refclock_receive(peer); 426182007Sroberto 427285612Sdelphij /* if (up->tcswitch >= MAXSTAGE) { */ 428285612Sdelphij write(pp->io.fd, COMMAND_HALT_BCAST, 2); 429285612Sdelphij /* } */ 43054359Sroberto} 43154359Sroberto 43254359Sroberto 43354359Sroberto/* 43454359Sroberto * arb_poll - called by the transmit procedure 43554359Sroberto */ 43654359Srobertostatic void 43754359Srobertoarb_poll( 43854359Sroberto int unit, 43954359Sroberto struct peer *peer 44054359Sroberto ) 44154359Sroberto{ 44254359Sroberto register struct arbunit *up; 44354359Sroberto struct refclockproc *pp; 44454359Sroberto 44554359Sroberto /* 44654359Sroberto * Time to poll the clock. The Arbiter clock responds to a "B5" 44754359Sroberto * by returning a timecode in the format specified above. 44854359Sroberto * Transmission occurs once per second, unless turned off by a 44954359Sroberto * "B0". Note there is no checking on state, since this may not 45054359Sroberto * be the only customer reading the clock. Only one customer 451182007Sroberto * need poll the clock; all others just listen in. 45254359Sroberto */ 45354359Sroberto pp = peer->procptr; 454285612Sdelphij up = pp->unitptr; 455182007Sroberto pp->polls++; 45654359Sroberto up->tcswitch = 0; 457182007Sroberto if (write(pp->io.fd, "TQ", 2) != 2) 45854359Sroberto refclock_report(peer, CEVNT_FAULT); 459182007Sroberto 460182007Sroberto /* 461182007Sroberto * Process median filter samples. If none received, declare a 462182007Sroberto * timeout and keep going. 463182007Sroberto */ 46454359Sroberto if (pp->coderecv == pp->codeproc) { 46554359Sroberto refclock_report(peer, CEVNT_TIMEOUT); 46654359Sroberto return; 46754359Sroberto } 468132451Sroberto refclock_receive(peer); 46954359Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 470182007Sroberto#ifdef DEBUG 471182007Sroberto if (debug) 472182007Sroberto printf("arbiter: timecode %d %s\n", 473182007Sroberto pp->lencode, pp->a_lastcode); 474182007Sroberto#endif 47554359Sroberto} 47654359Sroberto 47754359Sroberto#else 47854359Srobertoint refclock_arbiter_bs; 47954359Sroberto#endif /* REFCLOCK */ 480