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