STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_board_clock_sync.cpp
Go to the documentation of this file.
1
/**
2
* Unit tests for fsw::time::BoardClockSync (pure, deterministic — no sockets,
3
* no real clock). House style: plain main(), return 0 on pass / 1 on failure
4
* (see test_sequencer_elodin.cpp). Registered with CTest in lib/CMakeLists.txt.
5
*
6
* Edge-case matrix (from the time-sync design):
7
* 1. within-packet spreading 6. uint32 wrap mid-packet
8
* 2. min-filter under one-sided jitter 7. safety clamp → arrival fallback
9
* 3. crystal drift (both signs) 8. per-board monotonic guard
10
* 4. reboot → resync → re-lock 9. multi-board independence
11
* 5. uint32 wrap between packets 10. arrival mode (revert switch)
12
*/
13
14
#include <algorithm>
15
#include <cinttypes>
16
#include <cmath>
17
#include <cstdio>
18
#include <string>
19
#include <vector>
20
21
#include "
time/BoardClockSync.hpp
"
22
23
using
fsw::time::BoardClockSync
;
24
using
fsw::time::TimeSyncConfig
;
25
26
static
int
g_failures
= 0;
27
28
#define CHECK(cond, ...) \
29
do { \
30
if (!(cond)) { \
31
g_failures++; \
32
std::printf(" ❌ [%s:%d] ", __func__, __LINE__); \
33
std::printf(__VA_ARGS__); \
34
std::printf("\n"); \
35
} \
36
} while (0)
37
38
namespace
{
39
40
constexpr
uint64_t
NS_MS
= 1000000ULL;
41
constexpr
uint64_t
EPOCH
= 1800000000000000000ULL;
// arbitrary epoch-ns base
42
constexpr
uint64_t
U32_WRAP
= 4294967296ULL;
// 2^32
43
44
TimeSyncConfig
default_cfg
() {
45
TimeSyncConfig
cfg;
46
cfg.mode =
TimeSyncConfig::Mode::BoardClock
;
47
cfg.window_seconds = 10;
48
cfg.max_plausible_gap_s = 60;
49
cfg.max_batch_age_s = 5;
50
cfg.resync_threshold_ms = 1000;
51
return
cfg;
52
}
53
54
/** |a-b| for uint64 without underflow. */
55
uint64_t
absdiff
(uint64_t
a
, uint64_t
b
) {
56
return
a
>
b
?
a
-
b
:
b
-
a
;
57
}
58
59
/** Deterministic LCG so jitter sequences are reproducible. */
60
struct
Lcg
{
61
uint64_t
s
;
62
explicit
Lcg
(uint64_t seed) :
s
(seed) {
63
}
64
uint64_t
next
() {
65
s
=
s
* 6364136223846793005ULL + 1442695040888963407ULL;
66
return
s
>> 33;
67
}
68
uint64_t
below
(uint64_t
n
) {
69
return
next
() %
n
;
70
}
71
};
72
73
// ── 1. Within-packet spreading ───────────────────────────────────────────────
74
void
test_spreading
() {
75
BoardClockSync
sync(
default_cfg
());
76
// First packet: 3 chunks 100 ms apart; anchor = arrival.
77
const
uint64_t arrival =
EPOCH
;
78
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {1000, 1100, 1200});
79
CHECK
(out.size() == 3,
"expected 3 stamps"
);
80
CHECK
(out[2] == arrival,
"newest chunk must land on arrival (got delta %"
PRIu64
")"
,
81
absdiff
(out[2], arrival));
82
CHECK
(out[1] == arrival - 100 *
NS_MS
,
"middle chunk -100ms"
);
83
CHECK
(out[0] == arrival - 200 *
NS_MS
,
"oldest chunk -200ms"
);
84
CHECK
(sync.
stats
(
"b1"
).
locked
,
"board should be locked after first packet"
);
85
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 0,
"first packet is not a resync"
);
86
}
87
88
// ── 2. Min-filter under one-sided jitter (+ congestion immunity) ─────────────
89
void
test_min_filter_jitter
() {
90
BoardClockSync
sync(
default_cfg
());
91
// True relationship: send_time = EPOCH + board_ms. Delays one-sided, with a
92
// known minimum of 0 occurring periodically → offset should lock to truth.
93
const
uint64_t delays[] = {5, 17, 3, 0, 12, 8, 0, 22, 1, 15};
94
uint32_t board_ms = 1000;
95
uint64_t last = 0;
96
for
(
int
i = 0; i < 100; i++) {
97
const
uint64_t true_send =
EPOCH
+
static_cast<
uint64_t
>
(board_ms) *
NS_MS
;
98
const
uint64_t arrival = true_send + delays[i % 10] *
NS_MS
;
99
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {board_ms});
100
last = out[0];
101
board_ms += 100;
102
}
103
// After lock, every stamp should equal the true send time exactly (min=0 seen).
104
const
uint64_t true_last =
EPOCH
+
static_cast<
uint64_t
>
(board_ms - 100) *
NS_MS
;
105
CHECK
(
absdiff
(last, true_last) <= 1 *
NS_MS
,
"locked stamp off by %"
PRIu64
" ns"
,
106
absdiff
(last, true_last));
107
108
// Congestion burst: 20 packets all +50 ms late — stamps must stay true
109
// (the min-filter ignores one-sided delay; board time + offset is used).
110
for
(
int
i = 0; i < 20; i++) {
111
const
uint64_t true_send =
EPOCH
+
static_cast<
uint64_t
>
(board_ms) *
NS_MS
;
112
auto
out = sync.
stamp_packet
(
"b1"
, true_send + 50 *
NS_MS
, {board_ms});
113
CHECK
(
absdiff
(out[0], true_send) <= 1 *
NS_MS
,
114
"congested packet stamped %"
PRIu64
" ns off truth"
,
absdiff
(out[0], true_send));
115
board_ms += 100;
116
}
117
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 0,
"no resyncs expected under jitter/congestion"
);
118
CHECK
(sync.
stats
(
"b1"
).
jitter_ms
> 1.0,
"jitter stat should reflect the 50ms burst"
);
119
}
120
121
// ── 3. Crystal drift, both signs ─────────────────────────────────────────────
122
void
test_drift
() {
123
for
(
const
double
ppm : {+200.0, -200.0}) {
124
BoardClockSync
sync(
default_cfg
());
125
const
std::string key = ppm > 0 ?
"fast"
:
"slow"
;
126
uint64_t worst = 0;
127
// 60 s at 10 Hz; board clock runs at (1+ppm) rate; delivery delay 2 ms.
128
for
(
int
i = 0; i < 600; i++) {
129
const
double
real_s = 0.1 * i;
130
const
uint64_t true_send =
EPOCH
+
static_cast<
uint64_t
>
(real_s * 1e9);
131
const
uint32_t board_ms =
132
static_cast<
uint32_t
>
(1000.0 + real_s * 1000.0 * (1.0 + ppm * 1e-6));
133
auto
out = sync.
stamp_packet
(key, true_send + 2 *
NS_MS
, {board_ms});
134
if
(i > 100)
135
worst = std::max(worst,
absdiff
(out[0], true_send));
136
}
137
// Bound: delivery delay (2ms, constant → indistinguishable from offset)
138
// plus window staleness (10 s × 200 ppm = 2 ms) plus ms quantization.
139
CHECK
(worst <= 6 *
NS_MS
,
"%s drift worst error %"
PRIu64
" ns (limit 6ms)"
, key.c_str(),
140
worst);
141
CHECK
(sync.
stats
(key).
resyncs
== 0,
"%s drift must not cause resyncs"
, key.c_str());
142
}
143
}
144
145
// ── 4. Reboot → resync → re-lock ─────────────────────────────────────────────
146
void
test_reboot
() {
147
BoardClockSync
sync(
default_cfg
());
148
uint64_t arrival =
EPOCH
;
149
uint32_t board_ms = 3000000;
// ~50 min uptime
150
uint64_t prev_stamp = 0;
151
for
(
int
i = 0; i < 50; i++) {
152
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {board_ms});
153
prev_stamp = out[0];
154
arrival += 100 *
NS_MS
;
155
board_ms += 100;
156
}
157
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 0,
"pre-reboot: no resyncs"
);
158
159
// Reboot: millis resets to ~0. Forward modular step ≈ 2^32 - uptime → huge.
160
board_ms = 5;
161
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {board_ms});
162
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 1,
"reboot must count exactly one resync"
);
163
CHECK
(out[0] == arrival,
"resync packet anchors at arrival"
);
164
CHECK
(out[0] >= prev_stamp,
"monotonicity across reboot"
);
165
166
// Re-locked: subsequent packets spread normally off the new anchor.
167
arrival += 100 *
NS_MS
;
168
board_ms += 100;
169
auto
out2 = sync.
stamp_packet
(
"b1"
, arrival, {
static_cast<
uint32_t
>
(board_ms - 50), board_ms});
170
CHECK
(out2[1] == arrival,
"post-reboot newest at arrival"
);
171
CHECK
(out2[0] == arrival - 50 *
NS_MS
,
"post-reboot spreading intact"
);
172
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 1,
"re-lock must not add resyncs"
);
173
}
174
175
// ── 5. uint32 wrap between packets ───────────────────────────────────────────
176
void
test_wrap_between_packets
() {
177
BoardClockSync
sync(
default_cfg
());
178
uint64_t arrival =
EPOCH
;
179
uint64_t board_ms64 =
U32_WRAP
- 2000;
// 2 s before wrap
180
uint64_t prev = 0;
181
for
(
int
i = 0; i < 50; i++) {
// crosses the wrap around i=20
182
const
uint32_t raw =
static_cast<
uint32_t
>
(board_ms64 & 0xFFFFFFFFULL);
183
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {raw});
184
if
(i > 0) {
185
CHECK
(out[0] - prev == 100 *
NS_MS
,
186
"spacing must stay exactly 100ms across the wrap (i=%d, got %"
PRIu64
")"
, i,
187
out[0] - prev);
188
}
189
prev = out[0];
190
arrival += 100 *
NS_MS
;
191
board_ms64 += 100;
192
}
193
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 0,
"a wrap is NOT a reboot — no resync"
);
194
CHECK
(sync.
stats
(
"b1"
).
clamp_fallbacks
== 0,
"no clamps across wrap"
);
195
}
196
197
// ── 6. uint32 wrap mid-packet ────────────────────────────────────────────────
198
void
test_wrap_mid_packet
() {
199
BoardClockSync
sync(
default_cfg
());
200
// Prime the board just before the wrap.
201
sync.
stamp_packet
(
"b1"
,
EPOCH
, {
static_cast<
uint32_t
>
(
U32_WRAP
- 400)});
202
// Packet whose chunks span the wrap: ...-200, -100, then 0 (=wrap), +100.
203
const
uint64_t arrival =
EPOCH
+ 300 *
NS_MS
;
204
auto
out = sync.
stamp_packet
(
205
"b1"
, arrival,
206
{
static_cast<
uint32_t
>
(
U32_WRAP
- 200),
static_cast<
uint32_t
>
(
U32_WRAP
- 100), 0, 100});
207
CHECK
(out[3] - out[2] == 100 *
NS_MS
,
"post-wrap spacing"
);
208
CHECK
(out[2] - out[1] == 100 *
NS_MS
,
"spacing across the wrap boundary"
);
209
CHECK
(out[1] - out[0] == 100 *
NS_MS
,
"pre-wrap spacing"
);
210
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 0,
"mid-packet wrap is not a resync"
);
211
CHECK
(sync.
stats
(
"b1"
).
clamp_fallbacks
== 0,
"mid-packet wrap must not clamp"
);
212
}
213
214
// ── 7. Safety clamp → flat arrival fallback ──────────────────────────────────
215
void
test_clamp_fallback
() {
216
BoardClockSync
sync(
default_cfg
());
217
sync.
stamp_packet
(
"b1"
,
EPOCH
, {1000});
218
// Chunk claiming to be 10 s older than the newest (> max_batch_age 5 s):
219
// plausible intra-packet step, but the stamp lands before the age floor.
220
const
uint64_t arrival =
EPOCH
+ 10100 *
NS_MS
;
221
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {1100, 11100});
222
CHECK
(out[0] == arrival,
"too-old chunk must fall back to arrival"
);
223
CHECK
(sync.
stats
(
"b1"
).
clamp_fallbacks
== 1,
"fallback must be counted"
);
224
CHECK
(out[1] == arrival,
"newest chunk at arrival here"
);
225
226
// Garbage intra-packet spacing (backwards step > max gap): older chunk clamps.
227
const
uint64_t arrival2 = arrival + 100 *
NS_MS
;
228
auto
out2 = sync.
stamp_packet
(
"b1"
, arrival2, {900000000, 11200});
229
CHECK
(out2[0] == arrival2,
"garbage-spaced chunk must fall back to arrival"
);
230
CHECK
(sync.
stats
(
"b1"
).
clamp_fallbacks
== 2,
"second fallback counted"
);
231
// Invariant: nothing ever stamps in the future.
232
for
(
auto
t : out2)
233
CHECK
(t <= arrival2,
"no stamp may exceed arrival"
);
234
}
235
236
// ── 8. Per-board monotonic guard ─────────────────────────────────────────────
237
void
test_monotonic_guard
() {
238
BoardClockSync
sync(
default_cfg
());
239
// Packet 1 delayed 10 ms with an empty window → offset absorbs the delay.
240
const
uint64_t send1 =
EPOCH
+ 1000 *
NS_MS
;
241
auto
out1 = sync.
stamp_packet
(
"b1"
, send1 + 10 *
NS_MS
, {1000});
242
// Packet 2: board advances only 5 ms but delivery delay drops to 0 →
243
// naively t2 = t1 - 5ms. Guard must hold the line.
244
const
uint64_t send2 =
EPOCH
+ 1005 *
NS_MS
;
245
auto
out2 = sync.
stamp_packet
(
"b1"
, send2, {1005});
246
CHECK
(out2[0] >= out1[0],
"emitted stamps must be non-decreasing (got -%"
PRIu64
" ns)"
,
247
out1[0] > out2[0] ? out1[0] - out2[0] : 0);
248
}
249
250
// ── 9. Multi-board independence ──────────────────────────────────────────────
251
void
test_multi_board
() {
252
BoardClockSync
sync(
default_cfg
());
253
// Board A: normal. Board B: absurd absolute clock (offset ~ -1h), which is
254
// fine — offset is per-board. A reboot on B must not disturb A.
255
uint64_t arrival =
EPOCH
;
256
uint32_t a_ms = 1000, b_ms = 3600000;
257
uint64_t a_prev = 0;
258
for
(
int
i = 0; i < 30; i++) {
259
auto
oa = sync.
stamp_packet
(
"A"
, arrival + 1 *
NS_MS
, {a_ms});
260
sync.
stamp_packet
(
"B"
, arrival + 2 *
NS_MS
, {b_ms});
261
if
(i > 0)
262
CHECK
(oa[0] - a_prev == 100 *
NS_MS
,
"board A spacing exact"
);
263
a_prev = oa[0];
264
arrival += 100 *
NS_MS
;
265
a_ms += 100;
266
b_ms += 100;
267
}
268
sync.
stamp_packet
(
"B"
, arrival + 2 *
NS_MS
, {7});
// B reboots
269
CHECK
(sync.
stats
(
"B"
).
resyncs
== 1,
"B resynced"
);
270
CHECK
(sync.
stats
(
"A"
).
resyncs
== 0,
"A unaffected by B's reboot"
);
271
auto
oa = sync.
stamp_packet
(
"A"
, arrival + 100 *
NS_MS
+ 1 *
NS_MS
, {a_ms});
272
CHECK
(oa[0] - a_prev == 100 *
NS_MS
,
"A spacing exact after B's reboot"
);
273
}
274
275
// ── 10. Arrival mode (revert switch) ─────────────────────────────────────────
276
void
test_arrival_mode
() {
277
TimeSyncConfig
cfg =
default_cfg
();
278
cfg.mode =
TimeSyncConfig::Mode::Arrival
;
279
BoardClockSync
sync(cfg);
280
const
uint64_t arrival =
EPOCH
+ 42 *
NS_MS
;
281
auto
out = sync.
stamp_packet
(
"b1"
, arrival, {1000, 1100, 1200});
282
for
(
auto
t : out)
283
CHECK
(t == arrival,
"arrival mode: every chunk at arrival"
);
284
CHECK
(sync.
stats
(
"b1"
).
resyncs
== 0 && sync.
stats
(
"b1"
).
clamp_fallbacks
== 0,
285
"arrival mode touches no sync machinery"
);
286
}
287
288
// ── Fuzz: random jitter, invariants always hold ──────────────────────────────
289
void
test_fuzz_invariants
() {
290
BoardClockSync
sync(
default_cfg
());
291
Lcg
rng(0xD1AB70);
292
uint32_t board_ms = 500;
293
uint64_t arrival =
EPOCH
;
294
uint64_t prev = 0;
295
for
(
int
i = 0; i < 2000; i++) {
296
const
uint32_t n_chunks = 1 +
static_cast<
uint32_t
>
(rng.
below
(4));
297
std::vector<uint32_t>
chunks
;
298
for
(uint32_t c = 0; c < n_chunks; c++) {
299
chunks
.push_back(board_ms);
300
board_ms += 20 +
static_cast<
uint32_t
>
(rng.
below
(30));
301
}
302
arrival += (50 + rng.
below
(100)) *
NS_MS
;
// real time advances
303
const
uint64_t jittered = arrival + rng.
below
(40) *
NS_MS
;
// one-sided delay
304
auto
out = sync.
stamp_packet
(
"fz"
, jittered,
chunks
);
305
for
(
auto
t : out) {
306
CHECK
(t <= jittered,
"fuzz: stamp beyond arrival at i=%d"
, i);
307
CHECK
(t >= prev,
"fuzz: non-monotonic stamp at i=%d"
, i);
308
prev = t;
309
}
310
}
311
}
312
313
}
// namespace
314
315
int
main
() {
316
std::printf(
"BoardClockSync unit tests\n"
);
317
test_spreading
();
318
test_min_filter_jitter
();
319
test_drift
();
320
test_reboot
();
321
test_wrap_between_packets
();
322
test_wrap_mid_packet
();
323
test_clamp_fallback
();
324
test_monotonic_guard
();
325
test_multi_board
();
326
test_arrival_mode
();
327
test_fuzz_invariants
();
328
329
if
(
g_failures
== 0) {
330
std::printf(
"✅ all BoardClockSync tests passed\n"
);
331
return
0;
332
}
333
std::printf(
"❌ %d failure(s)\n"
,
g_failures
);
334
return
1;
335
}
BoardClockSync.hpp
Per-board clock sync for DAQ sample timestamping.
fsw::time::BoardClockSync
Definition
BoardClockSync.hpp:61
fsw::time::BoardClockSync::stamp_packet
std::vector< uint64_t > stamp_packet(const std::string &board_key, uint64_t arrival_ns, const std::vector< uint32_t > &chunk_ms)
Stamp one packet's chunks for one board.
Definition
BoardClockSync.cpp:42
fsw::time::BoardClockSync::stats
BoardStats stats(const std::string &board_key) const
Stats for one board (default-constructed if unknown).
Definition
BoardClockSync.cpp:153
chunks
std::vector< daq::SensorDataChunkCollection > chunks
Definition
main.cpp:55
b
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
Definition
json.hpp:13878
a
*brief create JSON pointer *sa reference_tokens const string_t & a
Definition
json.hpp:13877
anonymous_namespace{test_board_clock_sync.cpp}::test_clamp_fallback
void test_clamp_fallback()
Definition
test_board_clock_sync.cpp:215
anonymous_namespace{test_board_clock_sync.cpp}::test_min_filter_jitter
void test_min_filter_jitter()
Definition
test_board_clock_sync.cpp:89
anonymous_namespace{test_board_clock_sync.cpp}::absdiff
uint64_t absdiff(uint64_t a, uint64_t b)
|a-b| for uint64 without underflow.
Definition
test_board_clock_sync.cpp:55
anonymous_namespace{test_board_clock_sync.cpp}::test_spreading
void test_spreading()
Definition
test_board_clock_sync.cpp:74
anonymous_namespace{test_board_clock_sync.cpp}::EPOCH
constexpr uint64_t EPOCH
Definition
test_board_clock_sync.cpp:41
anonymous_namespace{test_board_clock_sync.cpp}::test_monotonic_guard
void test_monotonic_guard()
Definition
test_board_clock_sync.cpp:237
anonymous_namespace{test_board_clock_sync.cpp}::NS_MS
constexpr uint64_t NS_MS
Definition
test_board_clock_sync.cpp:40
anonymous_namespace{test_board_clock_sync.cpp}::test_multi_board
void test_multi_board()
Definition
test_board_clock_sync.cpp:251
anonymous_namespace{test_board_clock_sync.cpp}::U32_WRAP
constexpr uint64_t U32_WRAP
Definition
test_board_clock_sync.cpp:42
anonymous_namespace{test_board_clock_sync.cpp}::test_drift
void test_drift()
Definition
test_board_clock_sync.cpp:122
anonymous_namespace{test_board_clock_sync.cpp}::test_wrap_between_packets
void test_wrap_between_packets()
Definition
test_board_clock_sync.cpp:176
anonymous_namespace{test_board_clock_sync.cpp}::test_wrap_mid_packet
void test_wrap_mid_packet()
Definition
test_board_clock_sync.cpp:198
anonymous_namespace{test_board_clock_sync.cpp}::test_reboot
void test_reboot()
Definition
test_board_clock_sync.cpp:146
anonymous_namespace{test_board_clock_sync.cpp}::default_cfg
TimeSyncConfig default_cfg()
Definition
test_board_clock_sync.cpp:44
anonymous_namespace{test_board_clock_sync.cpp}::test_fuzz_invariants
void test_fuzz_invariants()
Definition
test_board_clock_sync.cpp:289
anonymous_namespace{test_board_clock_sync.cpp}::test_arrival_mode
void test_arrival_mode()
Definition
test_board_clock_sync.cpp:276
literals::json_literals::n
*brief user defined string literal for JSON values *sa std::size_t n
Definition
json.hpp:24474
anonymous_namespace{test_board_clock_sync.cpp}::Lcg
Deterministic LCG so jitter sequences are reproducible.
Definition
test_board_clock_sync.cpp:60
anonymous_namespace{test_board_clock_sync.cpp}::Lcg::s
uint64_t s
Definition
test_board_clock_sync.cpp:61
anonymous_namespace{test_board_clock_sync.cpp}::Lcg::below
uint64_t below(uint64_t n)
Definition
test_board_clock_sync.cpp:68
anonymous_namespace{test_board_clock_sync.cpp}::Lcg::next
uint64_t next()
Definition
test_board_clock_sync.cpp:64
anonymous_namespace{test_board_clock_sync.cpp}::Lcg::Lcg
Lcg(uint64_t seed)
Definition
test_board_clock_sync.cpp:62
fsw::time::BoardClockSync::BoardStats::jitter_ms
double jitter_ms
Definition
BoardClockSync.hpp:80
fsw::time::BoardClockSync::BoardStats::resyncs
uint32_t resyncs
Definition
BoardClockSync.hpp:81
fsw::time::BoardClockSync::BoardStats::locked
bool locked
Definition
BoardClockSync.hpp:84
fsw::time::BoardClockSync::BoardStats::clamp_fallbacks
uint32_t clamp_fallbacks
Definition
BoardClockSync.hpp:82
fsw::time::TimeSyncConfig
Definition
BoardClockSync.hpp:51
fsw::time::TimeSyncConfig::Mode::Arrival
@ Arrival
Definition
BoardClockSync.hpp:52
fsw::time::TimeSyncConfig::Mode::BoardClock
@ BoardClock
Definition
BoardClockSync.hpp:52
g_failures
static int g_failures
Definition
test_abort_ordering.cpp:52
CHECK
#define CHECK(cond,...)
Definition
test_board_clock_sync.cpp:28
main
int main()
Definition
test_board_clock_sync.cpp:315
daq-server
diablo_server
lib
test
test_board_clock_sync.cpp
Generated by
1.15.0