bare-time.c 2.67 KB
Newer Older
1
/*
2 3 4 5
 * Copyright (C) 2013 CERN (www.cern.ch)
 * Author: Alessandro Rubini
 *
 * Released to the public domain
6
 */
7

8
#include <ppsi/ppsi.h>
9
#include "bare-linux.h"
10

11
static int bare_time_get(struct pp_instance *ppi, TimeInternal *t)
12 13 14 15
{
	struct bare_timeval tv;

	if (sys_gettimeofday(&tv, NULL) < 0) {
16
		pp_error("%s:", __func__);
17
		sys_exit(1);
18
	}
19
	/* TAI = UTC + 35 */
20
	t->seconds = tv.tv_sec + DSPRO(ppi)->currentUtcOffset;
21
	t->nanoseconds = tv.tv_usec * 1000;
22
	if (!(pp_global_d_flags & PP_FLAG_NOTIMELOG))
23 24
		pp_diag(ppi, time, 2, "%s: %9li.%06li\n", __func__,
			tv.tv_sec, tv.tv_usec);
25 26 27
	return 0;
}

28
static int bare_time_set(struct pp_instance *ppi, TimeInternal *t)
29 30 31
{
	struct bare_timeval tv;

32 33 34 35 36 37 38 39
	if (!t) { /* Change the network notion of the utc/tai offset */
		struct bare_timex t;

		t.modes = MOD_TAI;
		t.constant = DSPRO(ppi)->currentUtcOffset;
		if (sys_adjtimex(&t) < 0)
			pp_diag(ppi, time, 1, "Can't change TAI offset");
		else
40
			pp_diag(ppi, time, 1, "New TAI offset: %i\n",
41 42 43 44
				DSPRO(ppi)->currentUtcOffset);
		return 0;
	}

45
	/* UTC = TAI - 35 */
46
	tv.tv_sec = t->seconds - DSPRO(ppi)->currentUtcOffset;
47 48 49
	tv.tv_usec = t->nanoseconds / 1000;

	if (sys_settimeofday(&tv, NULL) < 0) {
50
		pp_error("%s:", __func__);
51
		sys_exit(1);
52
	}
53 54
	pp_diag(ppi, time, 1, "%s: %9li.%06li\n", __func__, tv.tv_sec,
		tv.tv_usec);
55 56 57
	return 0;
}

58
static int bare_time_adjust(struct pp_instance *ppi, long offset_ns,
59
			    long freq_ppb)
60 61
{
	struct bare_timex t;
62
	int ret;
63

64 65
	/* FIXME: handle MOD_FREQUENCY and MOD_OFFSET separately, and
	 * set t.modes only for the mode having non-zero parameter.
66
	 * See unix_time_adjust in arch-unix/unix-time.c */
67 68 69 70
	if (freq_ppb > PP_ADJ_FREQ_MAX)
		freq_ppb = PP_ADJ_FREQ_MAX;
	if (freq_ppb < -PP_ADJ_FREQ_MAX)
		freq_ppb = -PP_ADJ_FREQ_MAX;
71 72

	t.offset = offset_ns / 1000;
73
	t.freq = freq_ppb * ((1 << 16) / 1000);
74 75
	t.modes = MOD_FREQUENCY | MOD_OFFSET;

76
	ret = sys_adjtimex(&t);
77
	pp_diag(ppi, time, 1, "%s: %li %li\n", __func__, offset_ns, freq_ppb);
78
	return ret;
79 80
}

81
static int bare_time_adjust_offset(struct pp_instance *ppi, long offset_ns)
82 83 84 85
{
	return bare_time_adjust(ppi, offset_ns, 0);
}

86
static int bare_time_adjust_freq(struct pp_instance *ppi, long freq_ppb)
87
{
88
	return bare_time_adjust(ppi, 0, freq_ppb);
89 90
}

91
static unsigned long bare_calc_timeout(struct pp_instance *ppi, int millisec)
92 93 94 95 96 97 98
{
	struct bare_timespec now;
	uint64_t now_ms;

	sys_clock_gettime(CLOCK_MONOTONIC, &now);
	now_ms = 1000LL * now.tv_sec + now.tv_nsec / 1000 / 1000;

99
	return now_ms + millisec;
100 101
}

102
struct pp_time_operations bare_time_ops = {
103 104 105
	.get = bare_time_get,
	.set = bare_time_set,
	.adjust = bare_time_adjust,
106 107
	.adjust_offset = bare_time_adjust_offset,
	.adjust_freq = bare_time_adjust_freq,
108
	.calc_timeout = bare_calc_timeout,
109
};