1 1.12 christos /* $NetBSD: refclock_acts.c,v 1.13 2024/08/18 20:47:18 christos Exp $ */ 2 1.1 kardel 3 1.1 kardel /* 4 1.1 kardel * refclock_acts - clock driver for the NIST/USNO/PTB/NPL Computer Time 5 1.1 kardel * Services 6 1.1 kardel */ 7 1.1 kardel #ifdef HAVE_CONFIG_H 8 1.1 kardel #include <config.h> 9 1.1 kardel #endif 10 1.1 kardel 11 1.6 christos #if defined(REFCLOCK) && defined(CLOCK_ACTS) 12 1.1 kardel 13 1.1 kardel #include "ntpd.h" 14 1.1 kardel #include "ntp_io.h" 15 1.1 kardel #include "ntp_unixtime.h" 16 1.1 kardel #include "ntp_refclock.h" 17 1.1 kardel #include "ntp_stdlib.h" 18 1.1 kardel #include "ntp_control.h" 19 1.1 kardel 20 1.1 kardel #include <stdio.h> 21 1.1 kardel #include <ctype.h> 22 1.1 kardel #ifdef HAVE_SYS_IOCTL_H 23 1.1 kardel # include <sys/ioctl.h> 24 1.1 kardel #endif /* HAVE_SYS_IOCTL_H */ 25 1.1 kardel 26 1.1 kardel /* 27 1.1 kardel * This driver supports the US (NIST, USNO) and European (PTB, NPL, 28 1.1 kardel * etc.) modem time services, as well as Spectracom GPS and WWVB 29 1.1 kardel * receivers connected via a modem. The driver periodically dials a 30 1.1 kardel * number from a telephone list, receives the timecode data and 31 1.1 kardel * calculates the local clock correction. It is designed primarily for 32 1.1 kardel * use as backup when neither a radio clock nor connectivity to Internet 33 1.1 kardel * time servers is available. 34 1.1 kardel * 35 1.1 kardel * This driver requires a modem with a Hayes-compatible command set and 36 1.1 kardel * control over the modem data terminal ready (DTR) control line. The 37 1.1 kardel * modem setup string is hard-coded in the driver and may require 38 1.6 christos * changes for nonstandard modems or special circumstances. 39 1.6 christos * 40 1.6 christos * When enabled, the calling program dials the first number in the 41 1.6 christos * phones file. If that call fails, it dials the second number and 42 1.6 christos * so on. The phone number is specified by the Hayes ATDT prefix 43 1.6 christos * followed by the number itself, including the long-distance prefix 44 1.6 christos * and delay code, if necessary. The calling program is enabled 45 1.6 christos * when (a) fudge flag1 is set by ntpdc, (b) at each poll interval 46 1.6 christos * when no other synchronization sources are present, and (c) at each 47 1.6 christos * poll interval whether or not other synchronization sources are 48 1.6 christos * present. The calling program disconnects if (a) the called party 49 1.6 christos * is busy or does not answer, (b) the called party disconnects 50 1.6 christos * before a sufficient nuimber of timecodes have been received. 51 1.1 kardel * 52 1.1 kardel * The driver is transparent to each of the modem time services and 53 1.1 kardel * Spectracom radios. It selects the parsing algorithm depending on the 54 1.1 kardel * message length. There is some hazard should the message be corrupted. 55 1.1 kardel * However, the data format is checked carefully and only if all checks 56 1.1 kardel * succeed is the message accepted. Corrupted lines are discarded 57 1.1 kardel * without complaint. 58 1.1 kardel * 59 1.1 kardel * Fudge controls 60 1.1 kardel * 61 1.1 kardel * flag1 force a call in manual mode 62 1.1 kardel * flag2 enable port locking (not verified) 63 1.6 christos * flag3 not used 64 1.1 kardel * flag4 not used 65 1.1 kardel * 66 1.1 kardel * time1 offset adjustment (s) 67 1.1 kardel * 68 1.6 christos * Ordinarily, the serial port is connected to a modem and the phones 69 1.6 christos * list is defined. If no phones list is defined, the port can be 70 1.6 christos * connected directly to a device or another computer. In this case the 71 1.6 christos * driver will send a single character 'T' at each poll event. If 72 1.6 christos * fudge flag2 is enabled, port locking allows the modem to be shared 73 1.6 christos * when not in use by this driver. 74 1.1 kardel */ 75 1.1 kardel /* 76 1.1 kardel * National Institute of Science and Technology (NIST) 77 1.1 kardel * 78 1.1 kardel * Phone: (303) 494-4774 (Boulder, CO); (808) 335-4721 (Hawaii) 79 1.1 kardel * 80 1.1 kardel * Data Format 81 1.1 kardel * 82 1.1 kardel * National Institute of Standards and Technology 83 1.1 kardel * Telephone Time Service, Generator 3B 84 1.1 kardel * Enter question mark "?" for HELP 85 1.1 kardel * D L D 86 1.1 kardel * MJD YR MO DA H M S ST S UT1 msADV <OTM> 87 1.1 kardel * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *<CR><LF> 88 1.1 kardel * ... 89 1.1 kardel * 90 1.1 kardel * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is 91 1.1 kardel * the on-time markers echoed by the driver and used by NIST to measure 92 1.6 christos * and correct for the propagation delay. Note: the ACTS timecode has 93 1.6 christos * recently been changed to eliminate the * on-time indicator. The 94 1.6 christos * reason for this and the long term implications are not clear. 95 1.1 kardel * 96 1.1 kardel * US Naval Observatory (USNO) 97 1.1 kardel * 98 1.1 kardel * Phone: (202) 762-1594 (Washington, DC); (719) 567-6742 (Boulder, CO) 99 1.1 kardel * 100 1.1 kardel * Data Format (two lines, repeating at one-second intervals) 101 1.1 kardel * 102 1.1 kardel * jjjjj nnn hhmmss UTC<CR><LF> 103 1.1 kardel * *<CR><LF> 104 1.1 kardel * 105 1.1 kardel * jjjjj modified Julian day number (not used) 106 1.1 kardel * nnn day of year 107 1.1 kardel * hhmmss second of day 108 1.1 kardel * * on-time marker for previous timecode 109 1.1 kardel * ... 110 1.1 kardel * 111 1.1 kardel * USNO does not correct for the propagation delay. A fudge time1 of 112 1.1 kardel * about .06 s is advisable. 113 1.1 kardel * 114 1.1 kardel * European Services (PTB, NPL, etc.) 115 1.1 kardel * 116 1.1 kardel * PTB: +49 531 512038 (Germany) 117 1.1 kardel * NPL: 0906 851 6333 (UK only) 118 1.1 kardel * 119 1.1 kardel * Data format (see the documentation for phone numbers and formats.) 120 1.1 kardel * 121 1.1 kardel * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500<CR><LF> 122 1.1 kardel * 123 1.1 kardel * Spectracom GPS and WWVB Receivers 124 1.1 kardel * 125 1.1 kardel * If a modem is connected to a Spectracom receiver, this driver will 126 1.1 kardel * call it up and retrieve the time in one of two formats. As this 127 1.1 kardel * driver does not send anything, the radio will have to either be 128 1.1 kardel * configured in continuous mode or be polled by another local driver. 129 1.1 kardel */ 130 1.1 kardel /* 131 1.1 kardel * Interface definitions 132 1.1 kardel */ 133 1.1 kardel #define DEVICE "/dev/acts%d" /* device name and unit */ 134 1.6 christos #define SPEED232 B19200 /* uart speed (19200 bps) */ 135 1.1 kardel #define PRECISION (-10) /* precision assumed (about 1 ms) */ 136 1.6 christos #define LOCKFILE "/var/spool/lock/LCK..cua%d" 137 1.1 kardel #define DESCRIPTION "Automated Computer Time Service" /* WRU */ 138 1.1 kardel #define REFID "NONE" /* default reference ID */ 139 1.1 kardel #define MSGCNT 20 /* max message count */ 140 1.1 kardel #define MAXPHONE 10 /* max number of phone numbers */ 141 1.1 kardel 142 1.1 kardel /* 143 1.6 christos * Calling program modes (mode) 144 1.1 kardel */ 145 1.6 christos #define MODE_BACKUP 0 /* backup mode */ 146 1.6 christos #define MODE_AUTO 1 /* automatic mode */ 147 1.1 kardel #define MODE_MANUAL 2 /* manual mode */ 148 1.1 kardel 149 1.1 kardel /* 150 1.6 christos * Service identifiers (message length) 151 1.1 kardel */ 152 1.1 kardel #define REFACTS "NIST" /* NIST reference ID */ 153 1.6 christos #define LENACTS 50 /* NIST format A */ 154 1.1 kardel #define REFUSNO "USNO" /* USNO reference ID */ 155 1.1 kardel #define LENUSNO 20 /* USNO */ 156 1.1 kardel #define REFPTB "PTB\0" /* PTB/NPL reference ID */ 157 1.1 kardel #define LENPTB 78 /* PTB/NPL format */ 158 1.1 kardel #define REFWWVB "WWVB" /* WWVB reference ID */ 159 1.1 kardel #define LENWWVB0 22 /* WWVB format 0 */ 160 1.1 kardel #define LENWWVB2 24 /* WWVB format 2 */ 161 1.1 kardel #define LF 0x0a /* ASCII LF */ 162 1.1 kardel 163 1.1 kardel /* 164 1.6 christos * Modem setup strings. These may have to be changed for 165 1.6 christos * some modems. 166 1.1 kardel * 167 1.1 kardel * AT command prefix 168 1.1 kardel * B1 US answer tone 169 1.1 kardel * &C0 disable carrier detect 170 1.1 kardel * &D2 hang up and return to command mode on DTR transition 171 1.1 kardel * E0 modem command echo disabled 172 1.6 christos * L1 set modem speaker volume to low level 173 1.1 kardel * M1 speaker enabled until carrier detect 174 1.1 kardel * Q0 return result codes 175 1.1 kardel * V1 return result codes as English words 176 1.6 christos * Y1 enable long-space disconnect 177 1.1 kardel */ 178 1.6 christos const char def_modem_setup[] = "ATB1&C0&D2E0L1M1Q0V1Y1"; 179 1.6 christos const char *modem_setup = def_modem_setup; 180 1.1 kardel 181 1.1 kardel /* 182 1.1 kardel * Timeouts (all in seconds) 183 1.1 kardel */ 184 1.1 kardel #define SETUP 3 /* setup timeout */ 185 1.6 christos #define REDIAL 30 /* redial timeout */ 186 1.1 kardel #define ANSWER 60 /* answer timeout */ 187 1.6 christos #define TIMECODE 60 /* message timeout */ 188 1.6 christos #define MAXCODE 20 /* max timecodes */ 189 1.1 kardel 190 1.1 kardel /* 191 1.1 kardel * State machine codes 192 1.1 kardel */ 193 1.6 christos typedef enum { 194 1.6 christos S_IDLE, /* wait for poll */ 195 1.6 christos S_SETUP, /* send modem setup */ 196 1.6 christos S_CONNECT, /* wait for answer */ 197 1.6 christos S_MSG /* wait for timecode */ 198 1.6 christos } teModemState; 199 1.1 kardel 200 1.1 kardel /* 201 1.1 kardel * Unit control structure 202 1.1 kardel */ 203 1.1 kardel struct actsunit { 204 1.1 kardel int unit; /* unit number */ 205 1.1 kardel int state; /* the first one was Delaware */ 206 1.1 kardel int timer; /* timeout counter */ 207 1.1 kardel int retry; /* retry index */ 208 1.1 kardel int msgcnt; /* count of messages received */ 209 1.1 kardel l_fp tstamp; /* on-time timestamp */ 210 1.6 christos char *bufptr; /* next incoming char stored here */ 211 1.6 christos char buf[BMAX]; /* bufptr roams within buf[] */ 212 1.1 kardel }; 213 1.1 kardel 214 1.1 kardel /* 215 1.1 kardel * Function prototypes 216 1.1 kardel */ 217 1.1 kardel static int acts_start (int, struct peer *); 218 1.1 kardel static void acts_shutdown (int, struct peer *); 219 1.1 kardel static void acts_receive (struct recvbuf *); 220 1.6 christos static void acts_message (struct peer *, const char *); 221 1.6 christos static void acts_timecode (struct peer *, const char *); 222 1.1 kardel static void acts_poll (int, struct peer *); 223 1.6 christos static void acts_timeout (struct peer *, teModemState); 224 1.1 kardel static void acts_timer (int, struct peer *); 225 1.6 christos static void acts_close (struct peer *); 226 1.1 kardel 227 1.1 kardel /* 228 1.1 kardel * Transfer vector (conditional structure name) 229 1.1 kardel */ 230 1.6 christos struct refclock refclock_acts = { 231 1.1 kardel acts_start, /* start up driver */ 232 1.1 kardel acts_shutdown, /* shut down driver */ 233 1.1 kardel acts_poll, /* transmit poll message */ 234 1.1 kardel noentry, /* not used */ 235 1.1 kardel noentry, /* not used */ 236 1.1 kardel noentry, /* not used */ 237 1.1 kardel acts_timer /* housekeeping timer */ 238 1.1 kardel }; 239 1.1 kardel 240 1.1 kardel /* 241 1.1 kardel * Initialize data for processing 242 1.1 kardel */ 243 1.1 kardel static int 244 1.6 christos acts_start( 245 1.1 kardel int unit, 246 1.1 kardel struct peer *peer 247 1.1 kardel ) 248 1.1 kardel { 249 1.1 kardel struct actsunit *up; 250 1.1 kardel struct refclockproc *pp; 251 1.6 christos const char *setup; 252 1.1 kardel 253 1.1 kardel /* 254 1.1 kardel * Allocate and initialize unit structure 255 1.1 kardel */ 256 1.6 christos up = emalloc_zero(sizeof(struct actsunit)); 257 1.1 kardel up->unit = unit; 258 1.1 kardel pp = peer->procptr; 259 1.6 christos pp->unitptr = up; 260 1.1 kardel pp->io.clock_recv = acts_receive; 261 1.6 christos pp->io.srcclock = peer; 262 1.1 kardel pp->io.datalen = 0; 263 1.6 christos pp->io.fd = -1; 264 1.1 kardel 265 1.1 kardel /* 266 1.1 kardel * Initialize miscellaneous variables 267 1.1 kardel */ 268 1.1 kardel peer->precision = PRECISION; 269 1.1 kardel pp->clockdesc = DESCRIPTION; 270 1.6 christos memcpy(&pp->refid, REFID, 4); 271 1.1 kardel peer->sstclktype = CTL_SST_TS_TELEPHONE; 272 1.6 christos up->bufptr = up->buf; 273 1.6 christos if (def_modem_setup == modem_setup) { 274 1.6 christos setup = get_ext_sys_var("modemsetup"); 275 1.6 christos if (setup != NULL) 276 1.6 christos modem_setup = estrdup(setup); 277 1.6 christos } 278 1.6 christos 279 1.1 kardel return (1); 280 1.1 kardel } 281 1.1 kardel 282 1.1 kardel 283 1.1 kardel /* 284 1.1 kardel * acts_shutdown - shut down the clock 285 1.1 kardel */ 286 1.1 kardel static void 287 1.6 christos acts_shutdown( 288 1.1 kardel int unit, 289 1.1 kardel struct peer *peer 290 1.1 kardel ) 291 1.1 kardel { 292 1.1 kardel struct actsunit *up; 293 1.1 kardel struct refclockproc *pp; 294 1.1 kardel 295 1.1 kardel /* 296 1.1 kardel * Warning: do this only when a call is not in progress. 297 1.1 kardel */ 298 1.1 kardel pp = peer->procptr; 299 1.6 christos up = pp->unitptr; 300 1.6 christos acts_close(peer); 301 1.1 kardel free(up); 302 1.1 kardel } 303 1.1 kardel 304 1.1 kardel 305 1.1 kardel /* 306 1.1 kardel * acts_receive - receive data from the serial interface 307 1.1 kardel */ 308 1.1 kardel static void 309 1.6 christos acts_receive( 310 1.1 kardel struct recvbuf *rbufp 311 1.1 kardel ) 312 1.1 kardel { 313 1.1 kardel struct actsunit *up; 314 1.1 kardel struct refclockproc *pp; 315 1.1 kardel struct peer *peer; 316 1.6 christos char tbuf[sizeof(up->buf)]; 317 1.6 christos char * tptr; 318 1.6 christos int octets; 319 1.1 kardel 320 1.1 kardel /* 321 1.1 kardel * Initialize pointers and read the timecode and timestamp. Note 322 1.1 kardel * we are in raw mode and victim of whatever the terminal 323 1.1 kardel * interface kicks up; so, we have to reassemble messages from 324 1.1 kardel * arbitrary fragments. Capture the timecode at the beginning of 325 1.1 kardel * the message and at the '*' and '#' on-time characters. 326 1.1 kardel */ 327 1.6 christos peer = rbufp->recv_peer; 328 1.1 kardel pp = peer->procptr; 329 1.6 christos up = pp->unitptr; 330 1.6 christos octets = sizeof(up->buf) - (up->bufptr - up->buf); 331 1.6 christos refclock_gtraw(rbufp, tbuf, octets, &pp->lastrec); 332 1.1 kardel for (tptr = tbuf; *tptr != '\0'; tptr++) { 333 1.1 kardel if (*tptr == LF) { 334 1.6 christos if (up->bufptr == up->buf) { 335 1.1 kardel up->tstamp = pp->lastrec; 336 1.1 kardel continue; 337 1.1 kardel } else { 338 1.1 kardel *up->bufptr = '\0'; 339 1.6 christos up->bufptr = up->buf; 340 1.6 christos acts_message(peer, up->buf); 341 1.1 kardel } 342 1.2 christos } else if (!iscntrl((unsigned char)*tptr)) { 343 1.1 kardel *up->bufptr++ = *tptr; 344 1.1 kardel if (*tptr == '*' || *tptr == '#') { 345 1.1 kardel up->tstamp = pp->lastrec; 346 1.13 christos refclock_write(peer, tptr, 1, "data"); 347 1.1 kardel } 348 1.1 kardel } 349 1.1 kardel } 350 1.1 kardel } 351 1.1 kardel 352 1.1 kardel 353 1.1 kardel /* 354 1.1 kardel * acts_message - process message 355 1.1 kardel */ 356 1.1 kardel void 357 1.1 kardel acts_message( 358 1.6 christos struct peer *peer, 359 1.6 christos const char *msg 360 1.1 kardel ) 361 1.1 kardel { 362 1.1 kardel struct actsunit *up; 363 1.1 kardel struct refclockproc *pp; 364 1.6 christos char tbuf[BMAX]; 365 1.6 christos int dtr = TIOCM_DTR; 366 1.6 christos 367 1.6 christos DPRINTF(1, ("acts: %d %s\n", (int)strlen(msg), msg)); 368 1.1 kardel 369 1.1 kardel /* 370 1.1 kardel * What to do depends on the state and the first token in the 371 1.6 christos * message. 372 1.6 christos */ 373 1.1 kardel pp = peer->procptr; 374 1.6 christos up = pp->unitptr; 375 1.1 kardel 376 1.1 kardel /* 377 1.6 christos * Extract the first token in the line. 378 1.1 kardel */ 379 1.6 christos strlcpy(tbuf, msg, sizeof(tbuf)); 380 1.1 kardel strtok(tbuf, " "); 381 1.6 christos switch (up->state) { 382 1.6 christos 383 1.6 christos /* 384 1.6 christos * We are waiting for the OK response to the modem setup 385 1.6 christos * command. When this happens, dial the number followed. 386 1.6 christos * If anything other than OK is received, just ignore it 387 1.6 christos * and wait for timeoue. 388 1.6 christos */ 389 1.6 christos case S_SETUP: 390 1.6 christos if (strcmp(tbuf, "OK") != 0) { 391 1.6 christos /* 392 1.6 christos * We disable echo with MODEM_SETUP's E0 but 393 1.6 christos * if the modem was previously E1, we will 394 1.6 christos * see MODEM_SETUP echoed before the OK/ERROR. 395 1.6 christos * Ignore it. 396 1.6 christos */ 397 1.6 christos if (!strcmp(tbuf, modem_setup)) 398 1.6 christos return; 399 1.6 christos break; 400 1.6 christos } 401 1.6 christos 402 1.6 christos mprintf_event(PEVNT_CLOCK, peer, "DIAL #%d %s", 403 1.6 christos up->retry, sys_phone[up->retry]); 404 1.6 christos if (ioctl(pp->io.fd, TIOCMBIS, &dtr) < 0) 405 1.6 christos msyslog(LOG_ERR, "acts: ioctl(TIOCMBIS) failed: %m"); 406 1.13 christos refclock_write(peer, sys_phone[up->retry], 407 1.13 christos strlen(sys_phone[up->retry]), 408 1.13 christos "DIAL"); 409 1.13 christos refclock_write(peer, "\r", 1, "CR"); 410 1.6 christos up->retry++; 411 1.6 christos up->state = S_CONNECT; 412 1.6 christos up->timer = ANSWER; 413 1.6 christos return; 414 1.6 christos 415 1.6 christos /* 416 1.6 christos * We are waiting for the CONNECT response to the dial 417 1.6 christos * command. When this happens, listen for timecodes. If 418 1.6 christos * somthing other than CONNECT is received, like BUSY 419 1.6 christos * or NO CARRIER, abort the call. 420 1.6 christos */ 421 1.6 christos case S_CONNECT: 422 1.6 christos if (strcmp(tbuf, "CONNECT") != 0) 423 1.6 christos break; 424 1.6 christos 425 1.6 christos report_event(PEVNT_CLOCK, peer, msg); 426 1.6 christos up->state = S_MSG; 427 1.6 christos up->timer = TIMECODE; 428 1.6 christos return; 429 1.6 christos 430 1.6 christos /* 431 1.6 christos * We are waiting for a timecode response. Pass it to 432 1.6 christos * the parser. If NO CARRIER is received, save the 433 1.6 christos * messages and abort the call. 434 1.6 christos */ 435 1.6 christos case S_MSG: 436 1.6 christos if (strcmp(tbuf, "NO") == 0) 437 1.6 christos report_event(PEVNT_CLOCK, peer, msg); 438 1.6 christos if (up->msgcnt < MAXCODE) 439 1.6 christos acts_timecode(peer, msg); 440 1.6 christos else 441 1.6 christos acts_timeout(peer, S_MSG); 442 1.1 kardel return; 443 1.1 kardel } 444 1.1 kardel 445 1.1 kardel /* 446 1.6 christos * Other response. Tell us about it. 447 1.6 christos */ 448 1.6 christos report_event(PEVNT_CLOCK, peer, msg); 449 1.6 christos acts_close(peer); 450 1.6 christos } 451 1.6 christos 452 1.6 christos 453 1.6 christos /* 454 1.6 christos * acts_timeout - called on timeout 455 1.6 christos */ 456 1.6 christos static void 457 1.6 christos acts_timeout( 458 1.6 christos struct peer *peer, 459 1.6 christos teModemState dstate 460 1.6 christos ) 461 1.6 christos { 462 1.6 christos struct actsunit *up; 463 1.6 christos struct refclockproc *pp; 464 1.6 christos int fd; 465 1.6 christos char device[20]; 466 1.6 christos char lockfile[128], pidbuf[8]; 467 1.6 christos 468 1.6 christos /* 469 1.6 christos * The state machine is driven by messages from the modem, 470 1.6 christos * when first started and at timeout. 471 1.6 christos */ 472 1.6 christos pp = peer->procptr; 473 1.6 christos up = pp->unitptr; 474 1.6 christos switch (dstate) { 475 1.6 christos 476 1.6 christos /* 477 1.6 christos * System poll event. Lock the modem port, open the device 478 1.6 christos * and send the setup command. 479 1.1 kardel */ 480 1.6 christos case S_IDLE: 481 1.6 christos if (-1 != pp->io.fd) 482 1.6 christos return; /* port is already open */ 483 1.6 christos 484 1.6 christos /* 485 1.6 christos * Lock the modem port. If busy, retry later. Note: if 486 1.6 christos * something fails between here and the close, the lock 487 1.6 christos * file may not be removed. 488 1.6 christos */ 489 1.6 christos if (pp->sloppyclockflag & CLK_FLAG2) { 490 1.6 christos snprintf(lockfile, sizeof(lockfile), LOCKFILE, 491 1.6 christos up->unit); 492 1.6 christos fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 493 1.6 christos 0644); 494 1.6 christos if (fd < 0) { 495 1.6 christos report_event(PEVNT_CLOCK, peer, "acts: port busy"); 496 1.6 christos return; 497 1.6 christos } 498 1.6 christos snprintf(pidbuf, sizeof(pidbuf), "%d\n", 499 1.6 christos (u_int)getpid()); 500 1.6 christos if (write(fd, pidbuf, strlen(pidbuf)) < 0) 501 1.6 christos msyslog(LOG_ERR, "acts: write lock fails %m"); 502 1.6 christos close(fd); 503 1.6 christos } 504 1.6 christos 505 1.6 christos /* 506 1.6 christos * Open the device in raw mode and link the I/O. 507 1.6 christos */ 508 1.6 christos snprintf(device, sizeof(device), DEVICE, 509 1.6 christos up->unit); 510 1.13 christos fd = refclock_open(&peer->srcadr, device, SPEED232, LDISC_ACTS | 511 1.6 christos LDISC_RAW | LDISC_REMOTE); 512 1.7 christos if (fd < 0) { 513 1.6 christos msyslog(LOG_ERR, "acts: open fails %m"); 514 1.6 christos return; 515 1.6 christos } 516 1.6 christos pp->io.fd = fd; 517 1.6 christos if (!io_addclock(&pp->io)) { 518 1.6 christos msyslog(LOG_ERR, "acts: addclock fails"); 519 1.6 christos close(fd); 520 1.6 christos pp->io.fd = -1; 521 1.6 christos return; 522 1.6 christos } 523 1.6 christos up->msgcnt = 0; 524 1.6 christos up->bufptr = up->buf; 525 1.6 christos 526 1.6 christos /* 527 1.6 christos * If the port is directly connected to the device, skip 528 1.6 christos * the modem business and send 'T' for Spectrabum. 529 1.6 christos */ 530 1.6 christos if (sys_phone[up->retry] == NULL) { 531 1.13 christos refclock_write(peer, "T", 1, "T"); 532 1.6 christos up->state = S_MSG; 533 1.6 christos up->timer = TIMECODE; 534 1.1 kardel return; 535 1.1 kardel } 536 1.6 christos 537 1.6 christos /* 538 1.6 christos * Initialize the modem. This works with Hayes- 539 1.6 christos * compatible modems. 540 1.6 christos */ 541 1.6 christos mprintf_event(PEVNT_CLOCK, peer, "SETUP %s", 542 1.6 christos modem_setup); 543 1.13 christos refclock_write(peer, modem_setup, strlen(modem_setup), 544 1.13 christos "SETUP"); 545 1.13 christos refclock_write(peer, "\r", 1, "CR"); 546 1.6 christos up->state = S_SETUP; 547 1.6 christos up->timer = SETUP; 548 1.1 kardel return; 549 1.1 kardel 550 1.1 kardel /* 551 1.6 christos * In SETUP state the modem did not respond OK to setup string. 552 1.6 christos */ 553 1.6 christos case S_SETUP: 554 1.6 christos report_event(PEVNT_CLOCK, peer, "no modem"); 555 1.6 christos break; 556 1.6 christos 557 1.6 christos /* 558 1.6 christos * In CONNECT state the call did not complete. Abort the call. 559 1.1 kardel */ 560 1.1 kardel case S_CONNECT: 561 1.6 christos report_event(PEVNT_CLOCK, peer, "no answer"); 562 1.6 christos break; 563 1.6 christos 564 1.6 christos /* 565 1.6 christos * In MSG states no further timecodes are expected. If any 566 1.6 christos * timecodes have arrived, update the clock. In any case, 567 1.6 christos * terminate the call. 568 1.6 christos */ 569 1.6 christos case S_MSG: 570 1.6 christos if (up->msgcnt == 0) { 571 1.6 christos report_event(PEVNT_CLOCK, peer, "no timecodes"); 572 1.6 christos } else { 573 1.6 christos pp->lastref = pp->lastrec; 574 1.6 christos record_clock_stats(&peer->srcadr, pp->a_lastcode); 575 1.6 christos refclock_receive(peer); 576 1.6 christos } 577 1.6 christos break; 578 1.6 christos } 579 1.6 christos acts_close(peer); 580 1.6 christos } 581 1.6 christos 582 1.6 christos 583 1.6 christos /* 584 1.6 christos * acts_close - close and prepare for next call. 585 1.6 christos * 586 1.6 christos * In ClOSE state no further protocol actions are required 587 1.6 christos * other than to close and release the device and prepare to 588 1.6 christos * dial the next number if necessary. 589 1.6 christos */ 590 1.6 christos void 591 1.6 christos acts_close( 592 1.6 christos struct peer *peer 593 1.6 christos ) 594 1.6 christos { 595 1.6 christos struct actsunit *up; 596 1.6 christos struct refclockproc *pp; 597 1.6 christos char lockfile[128]; 598 1.6 christos int dtr; 599 1.6 christos 600 1.6 christos pp = peer->procptr; 601 1.6 christos up = pp->unitptr; 602 1.6 christos if (pp->io.fd != -1) { 603 1.6 christos report_event(PEVNT_CLOCK, peer, "close"); 604 1.6 christos dtr = TIOCM_DTR; 605 1.6 christos if (ioctl(pp->io.fd, TIOCMBIC, &dtr) < 0) 606 1.6 christos msyslog(LOG_ERR, "acts: ioctl(TIOCMBIC) failed: %m"); 607 1.6 christos io_closeclock(&pp->io); 608 1.6 christos pp->io.fd = -1; 609 1.6 christos } 610 1.6 christos if (pp->sloppyclockflag & CLK_FLAG2) { 611 1.6 christos snprintf(lockfile, sizeof(lockfile), 612 1.6 christos LOCKFILE, up->unit); 613 1.6 christos unlink(lockfile); 614 1.6 christos } 615 1.6 christos if (up->msgcnt == 0 && up->retry > 0) { 616 1.6 christos if (sys_phone[up->retry] != NULL) { 617 1.6 christos up->state = S_IDLE; 618 1.6 christos up->timer = REDIAL; 619 1.1 kardel return; 620 1.1 kardel } 621 1.6 christos } 622 1.6 christos up->state = S_IDLE; 623 1.6 christos up->timer = 0; 624 1.6 christos } 625 1.6 christos 626 1.6 christos 627 1.6 christos /* 628 1.6 christos * acts_poll - called by the transmit routine 629 1.6 christos */ 630 1.6 christos static void 631 1.6 christos acts_poll( 632 1.6 christos int unit, 633 1.6 christos struct peer *peer 634 1.6 christos ) 635 1.6 christos { 636 1.6 christos struct actsunit *up; 637 1.6 christos struct refclockproc *pp; 638 1.6 christos 639 1.6 christos /* 640 1.6 christos * This routine is called at every system poll. All it does is 641 1.6 christos * set flag1 under certain conditions. The real work is done by 642 1.6 christos * the timeout routine and state machine. 643 1.6 christos */ 644 1.6 christos pp = peer->procptr; 645 1.6 christos up = pp->unitptr; 646 1.6 christos switch (peer->ttl) { 647 1.6 christos 648 1.6 christos /* 649 1.6 christos * In manual mode the calling program is activated by the ntpdc 650 1.6 christos * program using the enable flag (fudge flag1), either manually 651 1.6 christos * or by a cron job. 652 1.6 christos */ 653 1.6 christos case MODE_MANUAL: 654 1.1 kardel return; 655 1.1 kardel 656 1.1 kardel /* 657 1.6 christos * In automatic mode the calling program runs continuously at 658 1.6 christos * intervals determined by the poll event or specified timeout. 659 1.1 kardel */ 660 1.6 christos case MODE_AUTO: 661 1.6 christos break; 662 1.6 christos 663 1.6 christos /* 664 1.6 christos * In backup mode the calling program runs continuously as long 665 1.6 christos * as either no peers are available or this peer is selected. 666 1.6 christos */ 667 1.6 christos case MODE_BACKUP: 668 1.6 christos if (!(sys_peer == NULL || sys_peer == peer)) 669 1.6 christos return; 670 1.6 christos 671 1.1 kardel break; 672 1.1 kardel } 673 1.6 christos pp->polls++; 674 1.6 christos if (S_IDLE == up->state) { 675 1.6 christos up->retry = 0; 676 1.6 christos acts_timeout(peer, S_IDLE); 677 1.6 christos } 678 1.6 christos } 679 1.6 christos 680 1.6 christos 681 1.6 christos /* 682 1.6 christos * acts_timer - called at one-second intervals 683 1.6 christos */ 684 1.6 christos static void 685 1.6 christos acts_timer( 686 1.6 christos int unit, 687 1.6 christos struct peer *peer 688 1.6 christos ) 689 1.6 christos { 690 1.6 christos struct actsunit *up; 691 1.6 christos struct refclockproc *pp; 692 1.6 christos 693 1.6 christos /* 694 1.6 christos * This routine implments a timeout which runs for a programmed 695 1.6 christos * interval. The counter is initialized by the state machine and 696 1.6 christos * counts down to zero. Upon reaching zero, the state machine is 697 1.6 christos * called. If flag1 is set while timer is zero, force a call. 698 1.6 christos */ 699 1.6 christos pp = peer->procptr; 700 1.6 christos up = pp->unitptr; 701 1.6 christos if (up->timer == 0) { 702 1.6 christos if (pp->sloppyclockflag & CLK_FLAG1) { 703 1.6 christos pp->sloppyclockflag &= ~CLK_FLAG1; 704 1.6 christos acts_timeout(peer, S_IDLE); 705 1.6 christos } 706 1.6 christos } else { 707 1.6 christos up->timer--; 708 1.6 christos if (up->timer == 0) 709 1.6 christos acts_timeout(peer, up->state); 710 1.6 christos } 711 1.1 kardel } 712 1.1 kardel 713 1.1 kardel /* 714 1.1 kardel * acts_timecode - identify the service and parse the timecode message 715 1.1 kardel */ 716 1.1 kardel void 717 1.1 kardel acts_timecode( 718 1.6 christos struct peer * peer, /* peer structure pointer */ 719 1.6 christos const char * str /* timecode string */ 720 1.1 kardel ) 721 1.1 kardel { 722 1.1 kardel struct actsunit *up; 723 1.1 kardel struct refclockproc *pp; 724 1.1 kardel int day; /* day of the month */ 725 1.1 kardel int month; /* month of the year */ 726 1.1 kardel u_long mjd; /* Modified Julian Day */ 727 1.1 kardel double dut1; /* DUT adjustment */ 728 1.1 kardel 729 1.1 kardel u_int dst; /* ACTS daylight/standard time */ 730 1.1 kardel u_int leap; /* ACTS leap indicator */ 731 1.1 kardel double msADV; /* ACTS transmit advance (ms) */ 732 1.1 kardel char utc[10]; /* ACTS timescale */ 733 1.1 kardel char flag; /* ACTS on-time character (* or #) */ 734 1.1 kardel 735 1.1 kardel char synchar; /* WWVB synchronized indicator */ 736 1.1 kardel char qualchar; /* WWVB quality indicator */ 737 1.1 kardel char leapchar; /* WWVB leap indicator */ 738 1.1 kardel char dstchar; /* WWVB daylight/savings indicator */ 739 1.1 kardel int tz; /* WWVB timezone */ 740 1.1 kardel 741 1.3 christos int leapmonth; /* PTB/NPL month of leap */ 742 1.1 kardel char leapdir; /* PTB/NPL leap direction */ 743 1.1 kardel 744 1.1 kardel /* 745 1.1 kardel * The parser selects the modem format based on the message 746 1.1 kardel * length. Since the data are checked carefully, occasional 747 1.1 kardel * errors due noise are forgivable. 748 1.1 kardel */ 749 1.1 kardel pp = peer->procptr; 750 1.6 christos up = pp->unitptr; 751 1.1 kardel pp->nsec = 0; 752 1.6 christos switch (strlen(str)) { 753 1.1 kardel 754 1.1 kardel /* 755 1.1 kardel * For USNO format on-time character '*', which is on a line by 756 1.1 kardel * itself. Be sure a timecode has been received. 757 1.1 kardel */ 758 1.1 kardel case 1: 759 1.1 kardel if (*str == '*' && up->msgcnt > 0) 760 1.1 kardel break; 761 1.1 kardel 762 1.1 kardel return; 763 1.1 kardel 764 1.1 kardel /* 765 1.6 christos * ACTS format A: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa 766 1.6 christos * UTC(NIST) *". 767 1.1 kardel */ 768 1.1 kardel case LENACTS: 769 1.1 kardel if (sscanf(str, 770 1.1 kardel "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c", 771 1.1 kardel &mjd, &pp->year, &month, &day, &pp->hour, 772 1.1 kardel &pp->minute, &pp->second, &dst, &leap, &dut1, 773 1.1 kardel &msADV, utc, &flag) != 13) { 774 1.1 kardel refclock_report(peer, CEVNT_BADREPLY); 775 1.1 kardel return; 776 1.1 kardel } 777 1.1 kardel pp->day = ymd2yd(pp->year, month, day); 778 1.1 kardel pp->leap = LEAP_NOWARNING; 779 1.1 kardel if (leap == 1) 780 1.6 christos pp->leap = LEAP_ADDSECOND; 781 1.6 christos else if (leap == 2) 782 1.6 christos pp->leap = LEAP_DELSECOND; 783 1.1 kardel memcpy(&pp->refid, REFACTS, 4); 784 1.1 kardel up->msgcnt++; 785 1.6 christos if (flag != '#' && up->msgcnt < 10) 786 1.6 christos return; 787 1.6 christos 788 1.1 kardel break; 789 1.1 kardel 790 1.1 kardel /* 791 1.1 kardel * USNO format: "jjjjj nnn hhmmss UTC" 792 1.1 kardel */ 793 1.1 kardel case LENUSNO: 794 1.1 kardel if (sscanf(str, "%5ld %3d %2d%2d%2d %3s", 795 1.1 kardel &mjd, &pp->day, &pp->hour, &pp->minute, 796 1.1 kardel &pp->second, utc) != 6) { 797 1.1 kardel refclock_report(peer, CEVNT_BADREPLY); 798 1.1 kardel return; 799 1.1 kardel } 800 1.1 kardel 801 1.1 kardel /* 802 1.1 kardel * Wait for the on-time character, which follows in a 803 1.1 kardel * separate message. There is no provision for leap 804 1.1 kardel * warning. 805 1.1 kardel */ 806 1.1 kardel pp->leap = LEAP_NOWARNING; 807 1.1 kardel memcpy(&pp->refid, REFUSNO, 4); 808 1.1 kardel up->msgcnt++; 809 1.6 christos break; 810 1.1 kardel 811 1.1 kardel /* 812 1.1 kardel * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ" 813 1.1 kardel */ 814 1.1 kardel case LENPTB: 815 1.1 kardel if (sscanf(str, 816 1.1 kardel "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c", 817 1.1 kardel &pp->second, &pp->year, &month, &day, &pp->hour, 818 1.1 kardel &pp->minute, &mjd, &dut1, &leapdir, &leapmonth, 819 1.1 kardel &msADV, &flag) != 12) { 820 1.1 kardel refclock_report(peer, CEVNT_BADREPLY); 821 1.1 kardel return; 822 1.1 kardel } 823 1.1 kardel pp->leap = LEAP_NOWARNING; 824 1.1 kardel if (leapmonth == month) { 825 1.1 kardel if (leapdir == '+') 826 1.6 christos pp->leap = LEAP_ADDSECOND; 827 1.1 kardel else if (leapdir == '-') 828 1.6 christos pp->leap = LEAP_DELSECOND; 829 1.1 kardel } 830 1.1 kardel pp->day = ymd2yd(pp->year, month, day); 831 1.1 kardel memcpy(&pp->refid, REFPTB, 4); 832 1.1 kardel up->msgcnt++; 833 1.1 kardel break; 834 1.1 kardel 835 1.1 kardel 836 1.1 kardel /* 837 1.1 kardel * WWVB format 0: "I ddd hh:mm:ss DTZ=nn" 838 1.1 kardel */ 839 1.1 kardel case LENWWVB0: 840 1.1 kardel if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d", 841 1.1 kardel &synchar, &pp->day, &pp->hour, &pp->minute, 842 1.1 kardel &pp->second, &dstchar, &tz) != 7) { 843 1.1 kardel refclock_report(peer, CEVNT_BADREPLY); 844 1.1 kardel return; 845 1.1 kardel } 846 1.1 kardel pp->leap = LEAP_NOWARNING; 847 1.1 kardel if (synchar != ' ') 848 1.1 kardel pp->leap = LEAP_NOTINSYNC; 849 1.1 kardel memcpy(&pp->refid, REFWWVB, 4); 850 1.1 kardel up->msgcnt++; 851 1.1 kardel break; 852 1.1 kardel 853 1.1 kardel /* 854 1.1 kardel * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD" 855 1.1 kardel */ 856 1.1 kardel case LENWWVB2: 857 1.1 kardel if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c", 858 1.1 kardel &synchar, &qualchar, &pp->year, &pp->day, 859 1.1 kardel &pp->hour, &pp->minute, &pp->second, &pp->nsec, 860 1.1 kardel &dstchar, &leapchar, &dstchar) != 11) { 861 1.1 kardel refclock_report(peer, CEVNT_BADREPLY); 862 1.1 kardel return; 863 1.1 kardel } 864 1.1 kardel pp->nsec *= 1000000; 865 1.1 kardel pp->leap = LEAP_NOWARNING; 866 1.1 kardel if (synchar != ' ') 867 1.1 kardel pp->leap = LEAP_NOTINSYNC; 868 1.1 kardel else if (leapchar == 'L') 869 1.1 kardel pp->leap = LEAP_ADDSECOND; 870 1.1 kardel memcpy(&pp->refid, REFWWVB, 4); 871 1.1 kardel up->msgcnt++; 872 1.1 kardel break; 873 1.1 kardel 874 1.1 kardel /* 875 1.1 kardel * None of the above. Just forget about it and wait for the next 876 1.1 kardel * message or timeout. 877 1.1 kardel */ 878 1.1 kardel default: 879 1.1 kardel return; 880 1.1 kardel } 881 1.1 kardel 882 1.1 kardel /* 883 1.1 kardel * We have a valid timecode. The fudge time1 value is added to 884 1.1 kardel * each sample by the main line routines. Note that in current 885 1.1 kardel * telephone networks the propatation time can be different for 886 1.1 kardel * each call and can reach 200 ms for some calls. 887 1.1 kardel */ 888 1.1 kardel peer->refid = pp->refid; 889 1.1 kardel pp->lastrec = up->tstamp; 890 1.6 christos if (up->msgcnt == 0) 891 1.6 christos return; 892 1.6 christos 893 1.6 christos strlcpy(pp->a_lastcode, str, sizeof(pp->a_lastcode)); 894 1.6 christos pp->lencode = strlen(pp->a_lastcode); 895 1.1 kardel if (!refclock_process(pp)) { 896 1.1 kardel refclock_report(peer, CEVNT_BADTIME); 897 1.1 kardel return; 898 1.1 kardel } 899 1.1 kardel pp->lastref = pp->lastrec; 900 1.1 kardel } 901 1.1 kardel #else 902 1.13 christos NONEMPTY_TRANSLATION_UNIT 903 1.1 kardel #endif /* REFCLOCK */ 904