McStas Readout Master 0.8.0
Loading...
Searching...
No Matches
efu_time.h
1//
2// Created by g on 26/10/22.
3//
4
5#ifndef MCSTAS_UDP_TRANSMIT_EFU_TIME_H
6#define MCSTAS_UDP_TRANSMIT_EFU_TIME_H
7#include <chrono>
8#include <cmath>
9#include <iostream>
10#include <stdexcept>
11#include <utility>
12
19class efu_time {
20protected:
21 uint32_t _h;
22 uint32_t _l;
23public:
24 static constexpr uint64_t ticks = 88052499;
25
31 efu_time(const uint32_t high, const uint32_t low): _h(high), _l(low) {
32 if (_l > ticks) {
33 _h += _l / ticks;
34 _l %= ticks;
35 }
36 };
37
38 explicit efu_time(const std::pair<uint32_t, uint32_t> & p): _h(p.first), _l(p.second) {}
39
44 explicit efu_time(const double time)
45 : _h(static_cast<uint32_t>(time)), _l(static_cast<uint32_t>(std::fmod(time, 1.0) * ticks)) {}
46
50 efu_time(): _h(0), _l(0) {
51 using std::chrono::duration_cast, std::chrono::nanoseconds, std::chrono::system_clock;
52 constexpr uint64_t nps = 1000000000u; // nanoseconds per second
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);
58 }
59
60 uint32_t high() const {return _h;}
61 uint32_t low() const {return _l;}
62
63 bool operator==(const efu_time& other) const {
64 return (_h == other._h) && (_l == other._l);
65 }
66 bool operator<(const efu_time& other) const {
67 if (_h < other._h) return true;
68 if (_h > other._h) return false;
69 return _l < other._l;
70 }
71 bool operator>(const efu_time& other) const {
72 if (_h > other._h) return true;
73 if (_h < other._h) return false;
74 return _l > other._l;
75 }
76
77 bool operator>=(const efu_time & other) const {
78 return !(*this < other);
79 }
80
81 bool operator>=(const efu_time * other) const {
82 return *this >= *other;
83 }
84
85 efu_time operator+(const efu_time & other) const {
86 // the constructor ensures l is always less than ticks
87 // and 2*ticks is _well_ within the dynamic range of uint32_t
88 return {_h + other._h, _l + other._l};
89 }
90
91 efu_time operator+(const efu_time * other) const {
92 return *this + *other;
93 }
94
95 efu_time operator-(const efu_time & other) const {
96 if (*this < other) {
97 std::cout << *this << " - " << other << std::endl;
98 throw std::runtime_error("Subtracting a larger time?");
99 }
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)};
104 }
105
106 efu_time operator-(const efu_time * other) const {
107 return *this - *other;
108 }
109
110 uint64_t total_ticks() const {
111 return static_cast<uint64_t>(_h) * ticks + static_cast<uint64_t>(_l);
112 }
113
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;
117 }
118
120 static efu_time from_nanoseconds(const uint64_t ns) {
121 constexpr uint64_t nps = 1000000000u;
122 auto high = ns / nps;
123 auto low = ((ns % nps) * ticks + nps / 2) / nps;
124 if (low >= ticks) {
125 ++high;
126 low -= ticks;
127 }
128 return {static_cast<uint32_t>(high), static_cast<uint32_t>(low)};
129 }
130
132 static uint64_t now_nanoseconds() {
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());
135 }
136
137 uint32_t operator/(const efu_time & other) const {
138 return static_cast<uint32_t>(total_ticks() / other.total_ticks());
139 }
140
141 efu_time operator*(const uint32_t m) const {
142 auto h = _h * m;
143 auto r = static_cast<uint64_t>(_l) * static_cast<uint64_t>(m);
144 if (r > ticks){
145 h += static_cast<uint32_t>(r / ticks);
146 r = r % ticks;
147 }
148 return {h, static_cast<uint32_t>(r)};
149 }
150
151 efu_time operator%(const efu_time& m) const {
152 return *this - m * (*this / m);
153 }
154
155 efu_time operator%(const efu_time * m) const {
156 return *this % *m;
157 }
158
159 friend std::ostream& operator<<(std::ostream& os, const efu_time& dt) {
160 os << "(" << dt.high() << "," << dt.low() << ")";
161 return os;
162 }
163 friend std::ostream & operator<<(std::ostream& os, const efu_time* dt) {
164 os << "(" << dt->high() << "," << dt->low() << ")";
165 return os;
166 }
167};
168
178 uint64_t period_ns_;
179public:
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");
182 }
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)));
186 }
190 static pulse_grid from_period(const efu_time & period) {
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)));
193 }
194 [[nodiscard]] uint64_t period_ns() const { return period_ns_; }
195 [[nodiscard]] efu_time period() const { return efu_time::from_nanoseconds(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_; }
200};
201
202#endif // MCSTAS_UDP_TRANSMIT_EFU_TIME_H
ESS EFU two-integer timestamp: whole seconds since the UNIX epoch plus ticks of the 88....
Definition efu_time.h:19
efu_time(const double time)
Conversion from floating point time representation.
Definition efu_time.h:44
efu_time(const uint32_t high, const uint32_t low)
A time equivalent to that used in the ESS Event-Formation-Unit.
Definition efu_time.h:31
static efu_time from_nanoseconds(const uint64_t ns)
Nanoseconds since the UNIX epoch, to the nearest tick.
Definition efu_time.h:120
static uint64_t now_nanoseconds()
The system clock, in nanoseconds since the UNIX epoch.
Definition efu_time.h:132
efu_time()
Use the system clock to construct an EFU consistent time stamp.
Definition efu_time.h:50
The source's pulses: pulse k is at k periods after the UNIX epoch.
Definition efu_time.h:177
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,...
Definition efu_time.h:190
uint64_t after(const uint64_t ns) const
The first pulse strictly after ns.
Definition efu_time.h:199
uint64_t at_or_before(const uint64_t ns) const
The latest pulse at or before ns.
Definition efu_time.h:197