* hardpps() - discipline CPU clock oscillator to external PPS signal * * This routine is called at each PPS interrupt in order to discipline * the CPU clock oscillator to the PPS signal. There are two independent * first-order feedback loops, one for the phase, the other for the * frequency. The phase loop measures and grooms the PPS phase offset * and leaves it in a handy spot for the secon
| 771 | * nsec - hardware counter at PPS |
| 772 | */ |
| 773 | void |
| 774 | hardpps(struct timespec *tsp, long nsec) |
| 775 | { |
| 776 | long u_sec, u_nsec, v_nsec; /* temps */ |
| 777 | l_fp ftemp; |
| 778 | |
| 779 | NTP_LOCK(); |
| 780 | |
| 781 | /* |
| 782 | * The signal is first processed by a range gate and frequency |
| 783 | * discriminator. The range gate rejects noise spikes outside |
| 784 | * the range +-500 us. The frequency discriminator rejects input |
| 785 | * signals with apparent frequency outside the range 1 +-500 |
| 786 | * PPM. If two hits occur in the same second, we ignore the |
| 787 | * later hit; if not and a hit occurs outside the range gate, |
| 788 | * keep the later hit for later comparison, but do not process |
| 789 | * it. |
| 790 | */ |
| 791 | time_status |= STA_PPSSIGNAL | STA_PPSJITTER; |
| 792 | time_status &= ~(STA_PPSWANDER | STA_PPSERROR); |
| 793 | pps_valid = PPS_VALID; |
| 794 | u_sec = tsp->tv_sec; |
| 795 | u_nsec = tsp->tv_nsec; |
| 796 | if (u_nsec >= (NANOSECOND >> 1)) { |
| 797 | u_nsec -= NANOSECOND; |
| 798 | u_sec++; |
| 799 | } |
| 800 | v_nsec = u_nsec - pps_tf[0].tv_nsec; |
| 801 | if (u_sec == pps_tf[0].tv_sec && v_nsec < NANOSECOND - MAXFREQ) |
| 802 | goto out; |
| 803 | pps_tf[2] = pps_tf[1]; |
| 804 | pps_tf[1] = pps_tf[0]; |
| 805 | pps_tf[0].tv_sec = u_sec; |
| 806 | pps_tf[0].tv_nsec = u_nsec; |
| 807 | |
| 808 | /* |
| 809 | * Compute the difference between the current and previous |
| 810 | * counter values. If the difference exceeds 0.5 s, assume it |
| 811 | * has wrapped around, so correct 1.0 s. If the result exceeds |
| 812 | * the tick interval, the sample point has crossed a tick |
| 813 | * boundary during the last second, so correct the tick. Very |
| 814 | * intricate. |
| 815 | */ |
| 816 | u_nsec = nsec; |
| 817 | if (u_nsec > (NANOSECOND >> 1)) |
| 818 | u_nsec -= NANOSECOND; |
| 819 | else if (u_nsec < -(NANOSECOND >> 1)) |
| 820 | u_nsec += NANOSECOND; |
| 821 | pps_fcount += u_nsec; |
| 822 | if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ) |
| 823 | goto out; |
| 824 | time_status &= ~STA_PPSJITTER; |
| 825 | |
| 826 | /* |
| 827 | * A three-stage median filter is used to help denoise the PPS |
| 828 | * time. The median sample becomes the time offset estimate; the |
| 829 | * difference between the other two samples becomes the time |
| 830 | * dispersion (jitter) estimate. |
no test coverage detected