📄 refclock_acts.c
字号:
*/ case 1: if (*str == '*' && up->msgcnt > 0) break; return; /* * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa * UTC(NIST) *" */ case LENACTS: if (sscanf(str, "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c", &mjd, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, &dst, &leap, &dut1, &msADV, utc, &flag) != 13) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Wait until ACTS has calculated the roundtrip delay. * We don't need to do anything, as ACTS adjusts the * on-time epoch. */ if (flag != '#') return; pp->day = ymd2yd(pp->year, month, day); pp->leap = LEAP_NOWARNING; if (leap == 1) pp->leap = LEAP_ADDSECOND; else if (pp->leap == 2) pp->leap = LEAP_DELSECOND; memcpy(&pp->refid, REFACTS, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * USNO format: "jjjjj nnn hhmmss UTC" */ case LENUSNO: if (sscanf(str, "%5ld %3d %2d%2d%2d %3s", &mjd, &pp->day, &pp->hour, &pp->minute, &pp->second, utc) != 6) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Wait for the on-time character, which follows in a * separate message. There is no provision for leap * warning. */ pp->leap = LEAP_NOWARNING; memcpy(&pp->refid, REFUSNO, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; return; /* * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ" */ case LENPTB: if (sscanf(str, "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c", &pp->second, &pp->year, &month, &day, &pp->hour, &pp->minute, &mjd, &dut1, &leapdir, &leapmonth, &msADV, &flag) != 12) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->leap = LEAP_NOWARNING; if (leapmonth == month) { if (leapdir == '+') pp->leap = LEAP_ADDSECOND; else if (leapdir == '-') pp->leap = LEAP_DELSECOND; } pp->day = ymd2yd(pp->year, month, day); memcpy(&pp->refid, REFPTB, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * WWVB format 0: "I ddd hh:mm:ss DTZ=nn" */ case LENWWVB0: if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d", &synchar, &pp->day, &pp->hour, &pp->minute, &pp->second, &dstchar, &tz) != 7) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->leap = LEAP_NOWARNING; if (synchar != ' ') pp->leap = LEAP_NOTINSYNC; memcpy(&pp->refid, REFWWVB, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD" */ case LENWWVB2: if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c", &synchar, &qualchar, &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec, &dstchar, &leapchar, &dstchar) != 11) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->nsec *= 1000000; pp->leap = LEAP_NOWARNING; if (synchar != ' ') pp->leap = LEAP_NOTINSYNC; else if (leapchar == 'L') pp->leap = LEAP_ADDSECOND; memcpy(&pp->refid, REFWWVB, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * None of the above. Just forget about it and wait for the next * message or timeout. */ default: return; } /* * We have a valid timecode. The fudge time1 value is added to * each sample by the main line routines. Note that in current * telephone networks the propatation time can be different for * each call and can reach 200 ms for some calls. */ peer->refid = pp->refid; pp->lastrec = up->tstamp; if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; if (peer->disp > MAXDISTANCE) refclock_receive(peer); if (up->state != S_MSG) { up->state = S_MSG; up->timer = TIMECODE; }}/* * acts_poll - called by the transmit routine */static voidacts_poll ( int unit, struct peer *peer ){ struct actsunit *up; struct refclockproc *pp; /* * This routine is called at every system poll. All it does is * set flag1 under certain conditions. The real work is done by * the timeout routine and state machine. */ pp = peer->procptr; up = (struct actsunit *)pp->unitptr; switch (peer->ttl) { /* * In manual mode the calling program is activated by the ntpdc * program using the enable flag (fudge flag1), either manually * or by a cron job. */ case MODE_MANUAL: /* fall through */ break; /* * In automatic mode the calling program runs continuously at * intervals determined by the poll event or specified timeout. */ case MODE_AUTO: pp->sloppyclockflag |= CLK_FLAG1; break; /* * In backup mode the calling program runs continuously as long * as either no peers are available or this peer is selected. */ case MODE_BACKUP: if (sys_peer == NULL || sys_peer == peer) pp->sloppyclockflag |= CLK_FLAG1; break; }}/* * acts_timer - called at one-second intervals */static voidacts_timer( int unit, struct peer *peer ){ struct actsunit *up; struct refclockproc *pp; /* * This routine implments a timeout which runs for a programmed * interval. The counter is initialized by the state machine and * counts down to zero. Upon reaching zero, the state machine is * called. If flag1 is set while in S_IDLE state, force a * timeout. */ pp = peer->procptr; up = (struct actsunit *)pp->unitptr; if (pp->sloppyclockflag & CLK_FLAG1 && up->state == S_IDLE) { acts_timeout(peer); return; } if (up->timer == 0) return; up->timer--; if (up->timer == 0) acts_timeout(peer);}/* * acts_timeout - called on timeout */static voidacts_timeout( struct peer *peer ){ struct actsunit *up; struct refclockproc *pp; int fd; char device[20]; char lockfile[128], pidbuf[8]; char tbuf[BMAX]; /* * The state machine is driven by messages from the modem, when * first stated and at timeout. */ pp = peer->procptr; up = (struct actsunit *)pp->unitptr; pp->sloppyclockflag &= ~CLK_FLAG1; if (sys_phone[up->retry] == NULL && !(pp->sloppyclockflag & CLK_FLAG3)) { msyslog(LOG_ERR, "acts: no phones"); return; } switch(up->state) { /* * System poll event. Lock the modem port and open the device. */ case S_IDLE: /* * Lock the modem port. If busy, retry later. Note: if * something fails between here and the close, the lock * file may not be removed. */ if (pp->sloppyclockflag & CLK_FLAG2) { sprintf(lockfile, LOCKFILE, up->unit); fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0644); if (!fd) { msyslog(LOG_ERR, "acts: port busy"); return; } sprintf(pidbuf, "%d\n", (u_int)getpid()); write(fd, pidbuf, strlen(pidbuf)); close(fd); } /* * Open the device in raw mode and link the I/O. */ if (!pp->io.fd) { sprintf(device, DEVICE, up->unit); fd = refclock_open(device, SPEED232, LDISC_ACTS | LDISC_RAW | LDISC_REMOTE); if (fd == 0) { return; } pp->io.fd = fd; if (!io_addclock(&pp->io)) { msyslog(LOG_ERR, "acts: addclock fails"); close(fd); pp->io.fd = 0; return; } } /* * If the port is directly connected to the device, skip * the modem business and send 'T' for Spectrabum. */ if (pp->sloppyclockflag & CLK_FLAG3) { if (write(pp->io.fd, "T", 1) < 0) { msyslog(LOG_ERR, "acts: write %m"); return; } up->state = S_FIRST; up->timer = CONNECT; return; } /* * Initialize the modem. This works with Hayes commands. */#ifdef DEBUG if (debug) printf("acts: setup %s\n", MODEM_SETUP);#endif if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) < 0) { msyslog(LOG_ERR, "acts: write %m"); return; } up->state = S_OK; up->timer = SETUP; return; /* * In OK state the modem did not respond to setup. */ case S_OK: msyslog(LOG_ERR, "acts: no modem"); break; /* * In DTR state we are waiting for the modem to settle down * before hammering it with a dial command. */ case S_DTR: sprintf(tbuf, "DIAL #%d %s", up->retry, sys_phone[up->retry]); record_clock_stats(&peer->srcadr, tbuf);#ifdef DEBUG if (debug) printf("%s\n", tbuf);#endif write(pp->io.fd, sys_phone[up->retry], strlen(sys_phone[up->retry])); write(pp->io.fd, "\r", 1); up->state = S_CONNECT; up->timer = ANSWER; return; /* * In CONNECT state the call did not complete. */ case S_CONNECT: msyslog(LOG_ERR, "acts: no answer"); break; /* * In FIRST state no messages were received. */ case S_FIRST: msyslog(LOG_ERR, "acts: no messages"); break; /* * In CLOSE state hangup is complete. Close the doors and * windows and get some air. */ case S_CLOSE: /* * Close the device and unlock a shared modem. */ if (pp->io.fd) { io_closeclock(&pp->io); close(pp->io.fd); if (pp->sloppyclockflag & CLK_FLAG2) { sprintf(lockfile, LOCKFILE, up->unit); unlink(lockfile); } pp->io.fd = 0; } /* * If messages were received, fold the tent and wait for * the next poll. If no messages and there are more * numbers to dial, retry after a short wait. */ up->bufptr = pp->a_lastcode; up->timer = 0; up->state = S_IDLE; if ( up->msgcnt == 0) { up->retry++; if (sys_phone[up->retry] == NULL) up->retry = 0; else up->timer = SETUP; } else { up->retry = 0; } up->msgcnt = 0; return; } acts_disc(peer);}/* * acts_disc - disconnect the call and clean the place up. */static voidacts_disc ( struct peer *peer ){ struct actsunit *up; struct refclockproc *pp; int dtr = TIOCM_DTR; /* * We get here if the call terminated successfully or if an * error occured. If the median filter has something in it,feed * the data to the clock filter. If a modem port, drop DTR to * force command mode and send modem hangup. */ pp = peer->procptr; up = (struct actsunit *)pp->unitptr; if (up->msgcnt > 0) refclock_receive(peer); if (!(pp->sloppyclockflag & CLK_FLAG3)) { ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr); write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP)); } up->timer = SETUP; up->state = S_CLOSE;}#elseint refclock_acts_bs;#endif /* REFCLOCK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -