5#ifndef MCSTAS_UDP_TRANSMIT_EFU_TIME_H
6#define MCSTAS_UDP_TRANSMIT_EFU_TIME_H
24 static constexpr uint64_t ticks = 88052499;
31 efu_time(
const uint32_t high,
const uint32_t low): _h(high), _l(low) {
38 explicit efu_time(
const std::pair<uint32_t, uint32_t> & p): _h(p.first), _l(p.second) {}
45 : _h(static_cast<uint32_t>(time)), _l(static_cast<uint32_t>(std::fmod(time, 1.0) * ticks)) {}
51 using std::chrono::duration_cast, std::chrono::nanoseconds, std::chrono::system_clock;
52 constexpr uint64_t nps = 1000000000u;
53 const auto ns = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
54 const auto seconds = ns / nps;
55 const auto tick_count = ((ns % nps) * ticks) / nps;
56 _h =
static_cast<uint32_t
>(seconds);
57 _l =
static_cast<uint32_t
>(tick_count);
60 uint32_t high()
const {
return _h;}
61 uint32_t low()
const {
return _l;}
63 bool operator==(
const efu_time& other)
const {
64 return (_h == other._h) && (_l == other._l);
66 bool operator<(
const efu_time& other)
const {
67 if (_h < other._h)
return true;
68 if (_h > other._h)
return false;
71 bool operator>(
const efu_time& other)
const {
72 if (_h > other._h)
return true;
73 if (_h < other._h)
return false;
77 bool operator>=(
const efu_time & other)
const {
78 return !(*
this < other);
81 bool operator>=(
const efu_time * other)
const {
82 return *
this >= *other;
88 return {_h + other._h, _l + other._l};
92 return *
this + *other;
97 std::cout << *
this <<
" - " << other << std::endl;
98 throw std::runtime_error(
"Subtracting a larger time?");
100 uint32_t h = _h - other._h;
101 if (_l >= other._l)
return {h, _l - other._l};
102 auto r = ticks +
static_cast<uint64_t
>(_l) -
static_cast<uint64_t
>(other._l);
103 return {h - 1u,
static_cast<uint32_t
>(r)};
107 return *
this - *other;
110 uint64_t total_ticks()
const {
111 return static_cast<uint64_t
>(_h) * ticks +
static_cast<uint64_t
>(_l);
114 uint64_t total_nanoseconds()
const {
115 constexpr uint64_t nps = 1000000000u;
116 return static_cast<uint64_t
>(_h) * nps + (
static_cast<uint64_t
>(_l) * nps) / ticks;
121 constexpr uint64_t nps = 1000000000u;
122 auto high = ns / nps;
123 auto low = ((ns % nps) * ticks + nps / 2) / nps;
128 return {
static_cast<uint32_t
>(high),
static_cast<uint32_t
>(low)};
133 using std::chrono::duration_cast, std::chrono::nanoseconds, std::chrono::system_clock;
134 return static_cast<uint64_t
>(duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count());
137 uint32_t operator/(
const efu_time & other)
const {
138 return static_cast<uint32_t
>(total_ticks() / other.total_ticks());
141 efu_time operator*(
const uint32_t m)
const {
143 auto r =
static_cast<uint64_t
>(_l) *
static_cast<uint64_t
>(m);
145 h +=
static_cast<uint32_t
>(r / ticks);
148 return {h,
static_cast<uint32_t
>(r)};
152 return *
this - m * (*
this / m);
159 friend std::ostream& operator<<(std::ostream& os,
const efu_time& dt) {
160 os <<
"(" << dt.high() <<
"," << dt.low() <<
")";
163 friend std::ostream & operator<<(std::ostream& os,
const efu_time* dt) {
164 os <<
"(" << dt->high() <<
"," << dt->low() <<
")";
180 explicit pulse_grid(
const uint64_t period_ns): period_ns_(period_ns) {
181 if (period_ns_ == 0)
throw std::invalid_argument(
"pulse_grid period must be positive");
183 static pulse_grid from_rate(
const double rate) {
184 if (!(rate > 0))
throw std::invalid_argument(
"pulse_grid rate must be positive");
185 return pulse_grid(
static_cast<uint64_t
>(std::llround(1e9 / rate)));
191 const auto ns =
static_cast<double>(period.total_ticks()) * 1e9 /
static_cast<double>(efu_time::ticks);
192 return pulse_grid(
static_cast<uint64_t
>(std::llround(ns)));
194 [[nodiscard]] uint64_t period_ns()
const {
return period_ns_; }
197 [[nodiscard]] uint64_t
at_or_before(
const uint64_t ns)
const {
return ns / period_ns_ * period_ns_; }
199 [[nodiscard]] uint64_t
after(
const uint64_t ns)
const {
return (ns / period_ns_ + 1) * period_ns_; }
ESS EFU two-integer timestamp: whole seconds since the UNIX epoch plus ticks of the 88....
efu_time(const double time)
Conversion from floating point time representation.
efu_time(const uint32_t high, const uint32_t low)
A time equivalent to that used in the ESS Event-Formation-Unit.
static efu_time from_nanoseconds(const uint64_t ns)
Nanoseconds since the UNIX epoch, to the nearest tick.
static uint64_t now_nanoseconds()
The system clock, in nanoseconds since the UNIX epoch.
efu_time()
Use the system clock to construct an EFU consistent time stamp.
The source's pulses: pulse k is at k periods after the UNIX epoch.
static pulse_grid from_period(const efu_time &period)
For a period given as a time: to the nearest nanosecond. efu_time(double) truncates to a whole tick,...
uint64_t after(const uint64_t ns) const
The first pulse strictly after ns.
uint64_t at_or_before(const uint64_t ns) const
The latest pulse at or before ns.