예제 #1
0
Boolean adjFreq(clockid_t clkid,  int adj)
{
	struct timex tx;
	int err;

	if (adj > ADJ_FREQ_MAX)
		adj = ADJ_FREQ_MAX;
	else if (adj < -ADJ_FREQ_MAX)
		adj = -ADJ_FREQ_MAX;

	memset(&tx, 0, sizeof(tx));
	tx.modes = ADJ_FREQUENCY;
	tx.freq = (long) (adj * 65.536);

	err = clock_adjtime(clkid, &tx);
	if (err < 0) {
		ERROR("failed adjust the PTP clock: %s\n", strerror(errno));
		return FALSE;
	}
	NOTIFY("adjusted system clock by %d\n", adj);
	return TRUE;
}
예제 #2
0
/* wake up when the system time changes underneath us */
static int sntp_clock_watch_setup(SNTPContext *sntp) {
        struct itimerspec its = { .it_value.tv_sec = TIME_T_MAX };
        _cleanup_close_ int fd = -1;
        sd_event *e;
        sd_event_source *source;
        int r;

        assert(sntp);
        assert(sntp->event_receive);

        fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
        if (fd < 0) {
                log_error("Failed to create timerfd: %m");
                return -errno;
        }

        if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
                log_error("Failed to set up timerfd: %m");
                return -errno;
        }

        e = sd_event_source_get_event(sntp->event_receive);
        r = sd_event_add_io(e, &source, fd, EPOLLIN, sntp_clock_watch, sntp);
        if (r < 0) {
                log_error("Failed to create clock watch event source: %s", strerror(-r));
                return r;
        }

        sd_event_source_unref(sntp->event_clock_watch);
        sntp->event_clock_watch = source;

        if (sntp->clock_watch_fd >= 0)
                close(sntp->clock_watch_fd);
        sntp->clock_watch_fd = fd;
        fd = -1;

        return 0;
}

static int sntp_adjust_clock(SNTPContext *sntp, double offset, int leap_sec) {
        struct timex tmx = {};
        int r;

        /*
         * For small deltas, tell the kernel to gradually adjust the system
         * clock to the NTP time, larger deltas are just directly set.
         *
         * Clear STA_UNSYNC, it will enable the kernel's 11-minute mode, which
         * syncs the system time periodically to the hardware clock.
         */
        if (offset < NTP_MAX_ADJUST && offset > -NTP_MAX_ADJUST) {
                tmx.modes |= ADJ_STATUS | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
                tmx.status = STA_PLL;
                tmx.offset = offset * 1000 * 1000;
                tmx.constant = log2i(sntp->poll_interval_usec / USEC_PER_SEC) - 6;
                tmx.maxerror = 0;
                tmx.esterror = 0;
                log_debug("  adjust (slew): %+f sec\n", (double)tmx.offset / USEC_PER_SEC);
        } else {
                tmx.modes = ADJ_SETOFFSET;
                d_to_tv(offset, &tmx.time);

                sntp->jumped = true;
                log_debug("  adjust (jump): %+f sec\n", tv_to_d(&tmx.time));
        }

        switch (leap_sec) {
        case 1:
                tmx.status |= STA_INS;
                break;
        case -1:
                tmx.status |= STA_DEL;
                break;
        }

        r = clock_adjtime(CLOCK_REALTIME, &tmx);
        if (r < 0)
                return r;

        log_debug("  status       : %04i %s\n"
                  "  time now     : %li.%06li\n"
                  "  constant     : %li\n"
                  "  offset       : %+f sec\n"
                  "  freq offset  : %+li (%+.3f ppm)\n",
                  tmx.status, tmx.status & STA_UNSYNC ? "" : "sync",
                  tmx.time.tv_sec, tmx.time.tv_usec,
                  tmx.constant,
                  (double)tmx.offset / USEC_PER_SEC,
                  tmx.freq, (double)tmx.freq / 65536);

        return 0;
}

static bool sntp_sample_spike_detection(SNTPContext *sntp, double offset, double delay) {
        unsigned int i, idx_cur, idx_new, idx_min;
        double jitter;
        double j;

        /* store the current data in our samples array */
        idx_cur = sntp->samples_idx;
        idx_new = (idx_cur + 1) % ELEMENTSOF(sntp->samples);
        sntp->samples_idx = idx_new;
        sntp->samples[idx_new].offset = offset;
        sntp->samples[idx_new].delay = delay;

        sntp->packet_count++;
        jitter = sntp->samples_jitter;

        /* calculate new jitter value from the RMS differences relative to the lowest delay sample */
        for (idx_min = idx_cur, i = 0; i < ELEMENTSOF(sntp->samples); i++)
                if (sntp->samples[i].delay > 0 && sntp->samples[i].delay < sntp->samples[idx_min].delay)
                        idx_min = i;

        j = 0;
        for (i = 0; i < ELEMENTSOF(sntp->samples); i++)
                j += square(sntp->samples[i].offset - sntp->samples[idx_min].offset);
        sntp->samples_jitter = sqrt(j / (ELEMENTSOF(sntp->samples) - 1));

        /* ignore samples when resyncing */
        if (sntp->poll_resync)
                return false;

        /* always accept offset if we are farther off than the round-trip delay */
        if (fabs(offset) > delay)
                return false;

        /* we need a few samples before looking at them */
        if (sntp->packet_count < 4)
                return false;

        /* do not accept anything worse than the maximum possible error of the best sample */
        if (fabs(offset) > sntp->samples[idx_min].delay)
                return true;

        /* compare the difference between the current offset to the previous offset and jitter */
        return fabs(offset - sntp->samples[idx_cur].offset) > 3 * jitter;
}
예제 #3
0
int main(int argc, char *argv[])
{
	struct ptp_clock_caps caps;
	struct ptp_extts_event event;
	struct ptp_extts_request extts_request;
	struct ptp_perout_request perout_request;
	struct timespec ts;
	struct timex tx;

	static timer_t timerid;
	struct itimerspec timeout;
	struct sigevent sigevent;

	char *progname;
	int c, cnt, fd;

	char *device = DEVICE;
	clockid_t clkid;
	int adjfreq = 0x7fffffff;
	int adjtime = 0;
	int capabilities = 0;
	int extts = 0;
	int gettime = 0;
	int oneshot = 0;
	int periodic = 0;
	int perout = -1;
	int pps = -1;
	int settime = 0;

	progname = strrchr(argv[0], '/');
	progname = progname ? 1+progname : argv[0];
	while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghp:P:st:v"))) {
		switch (c) {
		case 'a':
			oneshot = atoi(optarg);
			break;
		case 'A':
			periodic = atoi(optarg);
			break;
		case 'c':
			capabilities = 1;
			break;
		case 'd':
			device = optarg;
			break;
		case 'e':
			extts = atoi(optarg);
			break;
		case 'f':
			adjfreq = atoi(optarg);
			break;
		case 'g':
			gettime = 1;
			break;
		case 'p':
			perout = atoi(optarg);
			break;
		case 'P':
			pps = atoi(optarg);
			break;
		case 's':
			settime = 1;
			break;
		case 't':
			adjtime = atoi(optarg);
			break;
		case 'h':
			usage(progname);
			return 0;
		case '?':
		default:
			usage(progname);
			return -1;
		}
	}

	fd = open(device, O_RDWR);
	if (fd < 0) {
		fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
		return -1;
	}

	clkid = get_clockid(fd);
	if (CLOCK_INVALID == clkid) {
		fprintf(stderr, "failed to read clock id\n");
		return -1;
	}

	if (capabilities) {
		if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
			perror("PTP_CLOCK_GETCAPS");
		} else {
			printf("capabilities:\n"
			       "  %d maximum frequency adjustment (ppb)\n"
			       "  %d programmable alarms\n"
			       "  %d external time stamp channels\n"
			       "  %d programmable periodic signals\n"
			       "  %d pulse per second\n",
			       caps.max_adj,
			       caps.n_alarm,
			       caps.n_ext_ts,
			       caps.n_per_out,
			       caps.pps);
		}
	}

	if (0x7fffffff != adjfreq) {
		memset(&tx, 0, sizeof(tx));
		tx.modes = ADJ_FREQUENCY;
		tx.freq = ppb_to_scaled_ppm(adjfreq);
		if (clock_adjtime(clkid, &tx)) {
			perror("clock_adjtime");
		} else {
			puts("frequency adjustment okay");
		}
	}

	if (adjtime) {
		memset(&tx, 0, sizeof(tx));
		tx.modes = ADJ_SETOFFSET;
		tx.time.tv_sec = adjtime;
		tx.time.tv_usec = 0;
		if (clock_adjtime(clkid, &tx) < 0) {
			perror("clock_adjtime");
		} else {
			puts("time shift okay");
		}
	}

	if (gettime) {
		if (clock_gettime(clkid, &ts)) {
			perror("clock_gettime");
		} else {
			printf("clock time: %ld.%09ld or %s",
			       ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
		}
	}

	if (settime) {
		clock_gettime(CLOCK_REALTIME, &ts);
		if (clock_settime(clkid, &ts)) {
			perror("clock_settime");
		} else {
			puts("set time okay");
		}
	}

	if (extts) {
		memset(&extts_request, 0, sizeof(extts_request));
		extts_request.index = 0;
		extts_request.flags = PTP_ENABLE_FEATURE;
		if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
			perror("PTP_EXTTS_REQUEST");
			extts = 0;
		} else {
			puts("external time stamp request okay");
		}
		for (; extts; extts--) {
			cnt = read(fd, &event, sizeof(event));
			if (cnt != sizeof(event)) {
				perror("read");
				break;
			}
			printf("event index %u at %lld.%09u\n", event.index,
			       event.t.sec, event.t.nsec);
			fflush(stdout);
		}
		/* Disable the feature again. */
		extts_request.flags = 0;
		if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
			perror("PTP_EXTTS_REQUEST");
		}
	}

	if (oneshot) {
		install_handler(SIGALRM, handle_alarm);
		/* Create a timer. */
		sigevent.sigev_notify = SIGEV_SIGNAL;
		sigevent.sigev_signo = SIGALRM;
		if (timer_create(clkid, &sigevent, &timerid)) {
			perror("timer_create");
			return -1;
		}
		/* Start the timer. */
		memset(&timeout, 0, sizeof(timeout));
		timeout.it_value.tv_sec = oneshot;
		if (timer_settime(timerid, 0, &timeout, NULL)) {
			perror("timer_settime");
			return -1;
		}
		pause();
		timer_delete(timerid);
	}

	if (periodic) {
		install_handler(SIGALRM, handle_alarm);
		/* Create a timer. */
		sigevent.sigev_notify = SIGEV_SIGNAL;
		sigevent.sigev_signo = SIGALRM;
		if (timer_create(clkid, &sigevent, &timerid)) {
			perror("timer_create");
			return -1;
		}
		/* Start the timer. */
		memset(&timeout, 0, sizeof(timeout));
		timeout.it_interval.tv_sec = periodic;
		timeout.it_value.tv_sec = periodic;
		if (timer_settime(timerid, 0, &timeout, NULL)) {
			perror("timer_settime");
			return -1;
		}
		while (1) {
			pause();
		}
		timer_delete(timerid);
	}

	if (perout >= 0) {
		if (clock_gettime(clkid, &ts)) {
			perror("clock_gettime");
			return -1;
		}
		memset(&perout_request, 0, sizeof(perout_request));
		perout_request.index = 0;
		perout_request.start.sec = ts.tv_sec + 2;
		perout_request.start.nsec = 0;
		perout_request.period.sec = 0;
		perout_request.period.nsec = perout;
		if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
			perror("PTP_PEROUT_REQUEST");
		} else {
			puts("periodic output request okay");
		}
	}

	if (pps != -1) {
		int enable = pps ? 1 : 0;
		if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
			perror("PTP_ENABLE_PPS");
		} else {
			puts("pps for system time request okay");
		}
	}

	close(fd);
	return 0;
}
예제 #4
0
파일: testptp.c 프로젝트: 020gzh/linux
int main(int argc, char *argv[])
{
	struct ptp_clock_caps caps;
	struct ptp_extts_event event;
	struct ptp_extts_request extts_request;
	struct ptp_perout_request perout_request;
	struct ptp_pin_desc desc;
	struct timespec ts;
	struct timex tx;

	static timer_t timerid;
	struct itimerspec timeout;
	struct sigevent sigevent;

	struct ptp_clock_time *pct;
	struct ptp_sys_offset *sysoff;


	char *progname;
	unsigned int i;
	int c, cnt, fd;

	char *device = DEVICE;
	clockid_t clkid;
	int adjfreq = 0x7fffffff;
	int adjtime = 0;
	int capabilities = 0;
	int extts = 0;
	int gettime = 0;
	int index = 0;
	int list_pins = 0;
	int oneshot = 0;
	int pct_offset = 0;
	int n_samples = 0;
	int periodic = 0;
	int perout = -1;
	int pin_index = -1, pin_func;
	int pps = -1;
	int seconds = 0;
	int settime = 0;

	int64_t t1, t2, tp;
	int64_t interval, offset;

	progname = strrchr(argv[0], '/');
	progname = progname ? 1+progname : argv[0];
	while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
		switch (c) {
		case 'a':
			oneshot = atoi(optarg);
			break;
		case 'A':
			periodic = atoi(optarg);
			break;
		case 'c':
			capabilities = 1;
			break;
		case 'd':
			device = optarg;
			break;
		case 'e':
			extts = atoi(optarg);
			break;
		case 'f':
			adjfreq = atoi(optarg);
			break;
		case 'g':
			gettime = 1;
			break;
		case 'i':
			index = atoi(optarg);
			break;
		case 'k':
			pct_offset = 1;
			n_samples = atoi(optarg);
			break;
		case 'l':
			list_pins = 1;
			break;
		case 'L':
			cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
			if (cnt != 2) {
				usage(progname);
				return -1;
			}
			break;
		case 'p':
			perout = atoi(optarg);
			break;
		case 'P':
			pps = atoi(optarg);
			break;
		case 's':
			settime = 1;
			break;
		case 'S':
			settime = 2;
			break;
		case 't':
			adjtime = atoi(optarg);
			break;
		case 'T':
			settime = 3;
			seconds = atoi(optarg);
			break;
		case 'h':
			usage(progname);
			return 0;
		case '?':
		default:
			usage(progname);
			return -1;
		}
	}

	fd = open(device, O_RDWR);
	if (fd < 0) {
		fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
		return -1;
	}

	clkid = get_clockid(fd);
	if (CLOCK_INVALID == clkid) {
		fprintf(stderr, "failed to read clock id\n");
		return -1;
	}

	if (capabilities) {
		if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
			perror("PTP_CLOCK_GETCAPS");
		} else {
			printf("capabilities:\n"
			       "  %d maximum frequency adjustment (ppb)\n"
			       "  %d programmable alarms\n"
			       "  %d external time stamp channels\n"
			       "  %d programmable periodic signals\n"
			       "  %d pulse per second\n"
			       "  %d programmable pins\n"
			       "  %d cross timestamping\n",
			       caps.max_adj,
			       caps.n_alarm,
			       caps.n_ext_ts,
			       caps.n_per_out,
			       caps.pps,
			       caps.n_pins,
			       caps.cross_timestamping);
		}
	}

	if (0x7fffffff != adjfreq) {
		memset(&tx, 0, sizeof(tx));
		tx.modes = ADJ_FREQUENCY;
		tx.freq = ppb_to_scaled_ppm(adjfreq);
		if (clock_adjtime(clkid, &tx)) {
			perror("clock_adjtime");
		} else {
			puts("frequency adjustment okay");
		}
	}

	if (adjtime) {
		memset(&tx, 0, sizeof(tx));
		tx.modes = ADJ_SETOFFSET;
		tx.time.tv_sec = adjtime;
		tx.time.tv_usec = 0;
		if (clock_adjtime(clkid, &tx) < 0) {
			perror("clock_adjtime");
		} else {
			puts("time shift okay");
		}
	}

	if (gettime) {
		if (clock_gettime(clkid, &ts)) {
			perror("clock_gettime");
		} else {
			printf("clock time: %ld.%09ld or %s",
			       ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
		}
	}

	if (settime == 1) {
		clock_gettime(CLOCK_REALTIME, &ts);
		if (clock_settime(clkid, &ts)) {
			perror("clock_settime");
		} else {
			puts("set time okay");
		}
	}

	if (settime == 2) {
		clock_gettime(clkid, &ts);
		if (clock_settime(CLOCK_REALTIME, &ts)) {
			perror("clock_settime");
		} else {
			puts("set time okay");
		}
	}

	if (settime == 3) {
		ts.tv_sec = seconds;
		ts.tv_nsec = 0;
		if (clock_settime(clkid, &ts)) {
			perror("clock_settime");
		} else {
			puts("set time okay");
		}
	}

	if (extts) {
		memset(&extts_request, 0, sizeof(extts_request));
		extts_request.index = index;
		extts_request.flags = PTP_ENABLE_FEATURE;
		if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
			perror("PTP_EXTTS_REQUEST");
			extts = 0;
		} else {
			puts("external time stamp request okay");
		}
		for (; extts; extts--) {
			cnt = read(fd, &event, sizeof(event));
			if (cnt != sizeof(event)) {
				perror("read");
				break;
			}
			printf("event index %u at %lld.%09u\n", event.index,
			       event.t.sec, event.t.nsec);
			fflush(stdout);
		}
		/* Disable the feature again. */
		extts_request.flags = 0;
		if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
			perror("PTP_EXTTS_REQUEST");
		}
	}

	if (list_pins) {
		int n_pins = 0;
		if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
			perror("PTP_CLOCK_GETCAPS");
		} else {
			n_pins = caps.n_pins;
		}
		for (i = 0; i < n_pins; i++) {
			desc.index = i;
			if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
				perror("PTP_PIN_GETFUNC");
				break;
			}
			printf("name %s index %u func %u chan %u\n",
			       desc.name, desc.index, desc.func, desc.chan);
		}
	}

	if (oneshot) {
		install_handler(SIGALRM, handle_alarm);
		/* Create a timer. */
		sigevent.sigev_notify = SIGEV_SIGNAL;
		sigevent.sigev_signo = SIGALRM;
		if (timer_create(clkid, &sigevent, &timerid)) {
			perror("timer_create");
			return -1;
		}
		/* Start the timer. */
		memset(&timeout, 0, sizeof(timeout));
		timeout.it_value.tv_sec = oneshot;
		if (timer_settime(timerid, 0, &timeout, NULL)) {
			perror("timer_settime");
			return -1;
		}
		pause();
		timer_delete(timerid);
	}

	if (periodic) {
		install_handler(SIGALRM, handle_alarm);
		/* Create a timer. */
		sigevent.sigev_notify = SIGEV_SIGNAL;
		sigevent.sigev_signo = SIGALRM;
		if (timer_create(clkid, &sigevent, &timerid)) {
			perror("timer_create");
			return -1;
		}
		/* Start the timer. */
		memset(&timeout, 0, sizeof(timeout));
		timeout.it_interval.tv_sec = periodic;
		timeout.it_value.tv_sec = periodic;
		if (timer_settime(timerid, 0, &timeout, NULL)) {
			perror("timer_settime");
			return -1;
		}
		while (1) {
			pause();
		}
		timer_delete(timerid);
	}

	if (perout >= 0) {
		if (clock_gettime(clkid, &ts)) {
			perror("clock_gettime");
			return -1;
		}
		memset(&perout_request, 0, sizeof(perout_request));
		perout_request.index = index;
		perout_request.start.sec = ts.tv_sec + 2;
		perout_request.start.nsec = 0;
		perout_request.period.sec = 0;
		perout_request.period.nsec = perout;
		if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
			perror("PTP_PEROUT_REQUEST");
		} else {
			puts("periodic output request okay");
		}
	}

	if (pin_index >= 0) {
		memset(&desc, 0, sizeof(desc));
		desc.index = pin_index;
		desc.func = pin_func;
		desc.chan = index;
		if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
			perror("PTP_PIN_SETFUNC");
		} else {
			puts("set pin function okay");
		}
	}

	if (pps != -1) {
		int enable = pps ? 1 : 0;
		if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
			perror("PTP_ENABLE_PPS");
		} else {
			puts("pps for system time request okay");
		}
	}

	if (pct_offset) {
		if (n_samples <= 0 || n_samples > 25) {
			puts("n_samples should be between 1 and 25");
			usage(progname);
			return -1;
		}

		sysoff = calloc(1, sizeof(*sysoff));
		if (!sysoff) {
			perror("calloc");
			return -1;
		}
		sysoff->n_samples = n_samples;

		if (ioctl(fd, PTP_SYS_OFFSET, sysoff))
			perror("PTP_SYS_OFFSET");
		else
			puts("system and phc clock time offset request okay");

		pct = &sysoff->ts[0];
		for (i = 0; i < sysoff->n_samples; i++) {
			t1 = pctns(pct+2*i);
			tp = pctns(pct+2*i+1);
			t2 = pctns(pct+2*i+2);
			interval = t2 - t1;
			offset = (t2 + t1) / 2 - tp;

			printf("system time: %lld.%u\n",
				(pct+2*i)->sec, (pct+2*i)->nsec);
			printf("phc    time: %lld.%u\n",
				(pct+2*i+1)->sec, (pct+2*i+1)->nsec);
			printf("system time: %lld.%u\n",
				(pct+2*i+2)->sec, (pct+2*i+2)->nsec);
			printf("system/phc clock time offset is %" PRId64 " ns\n"
			       "system     clock time delay  is %" PRId64 " ns\n",
				offset, interval);
		}

		free(sysoff);
	}

	close(fd);
	return 0;
}
예제 #5
0
/* wake up when the system time changes underneath us */
static int manager_clock_watch_setup(Manager *m) {

        struct itimerspec its = {
                .it_value.tv_sec = TIME_T_MAX
        };

        int r;

        assert(m);

        m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
        safe_close(m->clock_watch_fd);

        m->clock_watch_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
        if (m->clock_watch_fd < 0) {
                log_error("Failed to create timerfd: %m");
                return -errno;
        }

        if (timerfd_settime(m->clock_watch_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
                log_error("Failed to set up timerfd: %m");
                return -errno;
        }

        r = sd_event_add_io(m->event, &m->event_clock_watch, m->clock_watch_fd, EPOLLIN, manager_clock_watch, m);
        if (r < 0) {
                log_error("Failed to create clock watch event source: %s", strerror(-r));
                return r;
        }

        return 0;
}

static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
        struct timex tmx = {};
        int r;

        assert(m);

        /*
         * For small deltas, tell the kernel to gradually adjust the system
         * clock to the NTP time, larger deltas are just directly set.
         */
        if (fabs(offset) < NTP_MAX_ADJUST) {
                tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
                tmx.status = STA_PLL;
                tmx.offset = offset * NSEC_PER_SEC;
                tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4;
                tmx.maxerror = 0;
                tmx.esterror = 0;
                log_debug("  adjust (slew): %+.3f sec\n", offset);
        } else {
                tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET;

                /* ADJ_NANO uses nanoseconds in the microseconds field */
                tmx.time.tv_sec = (long)offset;
                tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC;

                /* the kernel expects -0.3s as {-1, 7000.000.000} */
                if (tmx.time.tv_usec < 0) {
                        tmx.time.tv_sec  -= 1;
                        tmx.time.tv_usec += NSEC_PER_SEC;
                }

                m->jumped = true;
                log_debug("  adjust (jump): %+.3f sec\n", offset);
        }

        /*
         * An unset STA_UNSYNC will enable the kernel's 11-minute mode,
         * which syncs the system time periodically to the RTC.
         *
         * In case the RTC runs in local time, never touch the RTC,
         * we have no way to properly handle daylight saving changes and
         * mobile devices moving between time zones.
         */
        if (m->rtc_local_time)
                tmx.status |= STA_UNSYNC;

        switch (leap_sec) {
        case 1:
                tmx.status |= STA_INS;
                break;
        case -1:
                tmx.status |= STA_DEL;
                break;
        }

        r = clock_adjtime(CLOCK_REALTIME, &tmx);
        if (r < 0)
                return r;

        touch("/var/lib/systemd/clock");

        m->drift_ppm = tmx.freq / 65536;

        log_debug("  status       : %04i %s\n"
                  "  time now     : %li.%03llu\n"
                  "  constant     : %li\n"
                  "  offset       : %+.3f sec\n"
                  "  freq offset  : %+li (%i ppm)\n",
                  tmx.status, tmx.status & STA_UNSYNC ? "unsync" : "sync",
                  tmx.time.tv_sec, (unsigned long long) (tmx.time.tv_usec / NSEC_PER_MSEC),
                  tmx.constant,
                  (double)tmx.offset / NSEC_PER_SEC,
                  tmx.freq, m->drift_ppm);

        return 0;
}

static bool manager_sample_spike_detection(Manager *m, double offset, double delay) {
        unsigned int i, idx_cur, idx_new, idx_min;
        double jitter;
        double j;

        assert(m);

        m->packet_count++;

        /* ignore initial sample */
        if (m->packet_count == 1)
                return false;

        /* store the current data in our samples array */
        idx_cur = m->samples_idx;
        idx_new = (idx_cur + 1) % ELEMENTSOF(m->samples);
        m->samples_idx = idx_new;
        m->samples[idx_new].offset = offset;
        m->samples[idx_new].delay = delay;

        /* calculate new jitter value from the RMS differences relative to the lowest delay sample */
        jitter = m->samples_jitter;
        for (idx_min = idx_cur, i = 0; i < ELEMENTSOF(m->samples); i++)
                if (m->samples[i].delay > 0 && m->samples[i].delay < m->samples[idx_min].delay)
                        idx_min = i;

        j = 0;
        for (i = 0; i < ELEMENTSOF(m->samples); i++)
                j += square(m->samples[i].offset - m->samples[idx_min].offset);
        m->samples_jitter = sqrt(j / (ELEMENTSOF(m->samples) - 1));

        /* ignore samples when resyncing */
        if (m->poll_resync)
                return false;

        /* always accept offset if we are farther off than the round-trip delay */
        if (fabs(offset) > delay)
                return false;

        /* we need a few samples before looking at them */
        if (m->packet_count < 4)
                return false;

        /* do not accept anything worse than the maximum possible error of the best sample */
        if (fabs(offset) > m->samples[idx_min].delay)
                return true;

        /* compare the difference between the current offset to the previous offset and jitter */
        return fabs(offset - m->samples[idx_cur].offset) > 3 * jitter;
}