DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
TDEEth_binding_test.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3import sys
4from fddetdataformats import TDEEthFrame, TDEEthHeader
5
6
7NUM_CHANNELS = 64
8NUM_SAMPLES = 64
9ADC_MAX = (1 << 14) - 1 # 14-bit ADC
10
11
13 frame = TDEEthFrame()
14 if frame is None:
15 print("FAIL: TDEEthFrame default construction returned None")
16 return 1
17 size = TDEEthFrame.sizeof()
18 if size <= 0:
19 print(f"FAIL: TDEEthFrame.sizeof() returned {size}, expected > 0")
20 return 1
21 print(f"PASS: TDEEthFrame construction and sizeof={size}")
22 return 0
23
24
26 if TDEEthFrame.s_bits_per_adc != 14:
27 print(f"FAIL: TDEEthFrame.s_bits_per_adc expected 14, got {TDEEthFrame.s_bits_per_adc}")
28 return 1
29 if TDEEthFrame.s_num_channels != NUM_CHANNELS:
30 print(f"FAIL: TDEEthFrame.s_num_channels expected {NUM_CHANNELS}, got {TDEEthFrame.s_num_channels}")
31 return 1
32 if TDEEthFrame.s_time_samples_per_frame != NUM_SAMPLES:
33 print(f"FAIL: TDEEthFrame.s_time_samples_per_frame expected {NUM_SAMPLES}, got {TDEEthFrame.s_time_samples_per_frame}")
34 return 1
35 if TDEEthFrame.s_expected_bytes != TDEEthFrame.sizeof():
36 print(f"FAIL: TDEEthFrame.s_expected_bytes {TDEEthFrame.s_expected_bytes} != sizeof {TDEEthFrame.sizeof()}")
37 return 1
38 if TDEEthHeader.s_expected_bytes <= 0:
39 print(f"FAIL: TDEEthHeader.s_expected_bytes invalid: {TDEEthHeader.s_expected_bytes}")
40 return 1
41 print("PASS: TDEEthFrame/TDEEthHeader static members")
42 return 0
43
44
46 frame = TDEEthFrame()
47 frame.set_timestamp(0xDEADBEEFCAFE)
48 raw = frame.get_bytes()
49 if len(raw) != TDEEthFrame.sizeof():
50 print(f"FAIL: get_bytes() length {len(raw)} != sizeof() {TDEEthFrame.sizeof()}")
51 return 1
52 clone = TDEEthFrame(raw)
53 if clone.get_timestamp() != 0xDEADBEEFCAFE:
54 print(f"FAIL: bytes round-trip timestamp mismatch: got {clone.get_timestamp():#x}")
55 return 1
56 print("PASS: TDEEthFrame bytes constructor roundtrip")
57 return 0
58
59
61 earlier = TDEEthFrame()
62 later = TDEEthFrame()
63 earlier.set_timestamp(100)
64 later.set_timestamp(200)
65 if not (earlier < later):
66 print("FAIL: __lt__ expected earlier < later")
67 return 1
68 if later < earlier:
69 print("FAIL: __lt__ expected later !< earlier")
70 return 1
71 print("PASS: __lt__ ordering by timestamp")
72 return 0
73
74
75def test_timestamp() -> int:
76 frame = TDEEthFrame()
77 test_ts = 0x123456789ABC
78 frame.set_timestamp(test_ts)
79 got = frame.get_timestamp()
80 if got != test_ts:
81 print(f"FAIL: set/get_timestamp: set {test_ts:#x}, got {got:#x}")
82 return 1
83 print("PASS: set_timestamp / get_timestamp")
84 return 0
85
86
87def test_channel() -> int:
88 frame = TDEEthFrame()
89 for val in (0, 1, 127, 255):
90 frame.set_channel(val)
91 got = frame.get_channel()
92 if got != val:
93 print(f"FAIL: set_channel({val}), get_channel() returned {got}")
94 return 1
95 print("PASS: set_channel / get_channel")
96 return 0
97
98
100 frame = TDEEthFrame()
101 hdr = frame.daq_header
102 if hdr is None:
103 print("FAIL: daq_header returned None")
104 return 1
105 hdr_alias = frame.get_daqheader()
106 if hdr_alias is None:
107 print("FAIL: get_daqheader() returned None")
108 return 1
109 print("PASS: daq_header accessible")
110 return 0
111
112
113def test_set_geoid() -> int:
114 frame = TDEEthFrame()
115 crate_id = 11
116 slot_id = 12
117 stream_id = 33
118 frame.daq_header.crate_id = crate_id
119 frame.daq_header.slot_id = slot_id
120 frame.daq_header.stream_id = stream_id
121
122 if frame.daq_header.crate_id != crate_id:
123 print(f"FAIL: crate_id mismatch, got {frame.daq_header.crate_id}")
124 return 1
125 if frame.daq_header.slot_id != slot_id:
126 print(f"FAIL: slot_id mismatch, got {frame.daq_header.slot_id}")
127 return 1
128 if frame.daq_header.stream_id != stream_id:
129 print(f"FAIL: stream_id mismatch, got {frame.daq_header.stream_id}")
130 return 1
131
132 print("PASS: DAQEthHeader geoid fields set and read back via frame.daq_header")
133 return 0
134
135
137 frame = TDEEthFrame()
138 hdr_alias = frame.get_tdeheader()
139
140 if hdr_alias is None:
141 print("FAIL: get_tdeheader() returned None")
142 return 1
143
144 frame.header.channel = 42
145 if frame.header.channel != 42:
146 print(f"FAIL: TDEEthHeader.channel: set 42, got {frame.header.channel}")
147 return 1
148
149 frame.header.version = 3
150 if frame.header.version != 3:
151 print(f"FAIL: TDEEthHeader.version: set 3, got {frame.header.version}")
152 return 1
153
154 frame.header.tde_header = 0x1F
155 if frame.header.tde_header != 0x1F:
156 print(f"FAIL: TDEEthHeader.tde_header: set 0x1F, got {frame.header.tde_header:#x}")
157 return 1
158
159 frame.header.tde_errors = 0xAB
160 if frame.header.tde_errors != 0xAB:
161 print(f"FAIL: TDEEthHeader.tde_errors: set 0xAB, got {frame.header.tde_errors:#x}")
162 return 1
163
164 frame.header.TAItime = 0xFEDCBA9876543210
165 if frame.header.TAItime != 0xFEDCBA9876543210:
166 print(f"FAIL: TDEEthHeader.TAItime: set 0xFEDCBA9876543210, got {frame.header.TAItime:#x}")
167 return 1
168 if hdr_alias.TAItime != 0xFEDCBA9876543210:
169 print(f"FAIL: get_tdeheader alias mismatch, got {hdr_alias.TAItime:#x}")
170 return 1
171
172 print("PASS: TDEEthHeader property read/write and get_tdeheader alias")
173 return 0
174
175
176def test_adc_single() -> int: # noqa: E302
177 frame = TDEEthFrame()
178 # Write and read back a single ADC value in channel 0, sample 0
179 frame.set_adc(0, 0, 1234)
180 got = frame.get_adc(0, 0)
181 if got != 1234:
182 print(f"FAIL: set_adc(0,0,1234) -> get_adc(0,0) returned {got}")
183 return 1
184 print("PASS: single ADC set/get (channel 0, sample 0)")
185 return 0
186
187
189 frame = TDEEthFrame()
190 frame.set_adc(0, 0, ADC_MAX)
191 got = frame.get_adc(0, 0)
192 if got != ADC_MAX:
193 print(f"FAIL: max ADC value {ADC_MAX}: got {got}")
194 return 1
195 print(f"PASS: max ADC value ({ADC_MAX}) preserved")
196 return 0
197
198
200 """Verify that writing to one (channel, sample) cell does not corrupt its neighbours."""
201 frame = TDEEthFrame()
202
203 # Write distinct values to several cells
204 test_cases = [
205 (0, 0, 100),
206 (0, 1, 200),
207 (1, 0, 300),
208 (NUM_CHANNELS - 1, NUM_SAMPLES - 1, 9999),
209 ]
210 for ch, samp, val in test_cases:
211 frame.set_adc(ch, samp, val)
212
213 # Read them all back and check none leaked into each other
214 for ch, samp, expected in test_cases:
215 got = frame.get_adc(ch, samp)
216 if got != expected:
217 print(f"FAIL: ADC independence: channel={ch}, sample={samp}: expected {expected}, got {got}")
218 return 1
219
220 print("PASS: ADC cell independence across multiple (channel, sample) pairs")
221 return 0
222
223
225 """Write a unique value to every channel in sample 0 and verify all read back correctly."""
226 frame = TDEEthFrame()
227 for ch in range(NUM_CHANNELS):
228 frame.set_adc(ch, 0, ch * 100 % (ADC_MAX + 1))
229 for ch in range(NUM_CHANNELS):
230 expected = ch * 100 % (ADC_MAX + 1)
231 got = frame.get_adc(ch, 0)
232 if got != expected:
233 print(f"FAIL: all-channels test: channel {ch}: expected {expected}, got {got}")
234 return 1
235 print(f"PASS: all {NUM_CHANNELS} channels read back correctly for sample 0")
236 return 0
237
238
240 """get_adc / set_adc should raise when indices are out of range."""
241 frame = TDEEthFrame()
242 try:
243 frame.get_adc(NUM_CHANNELS, 0)
244 print("FAIL: get_adc with out-of-range channel should have raised an exception")
245 return 1
246 except Exception:
247 pass
248 try:
249 frame.get_adc(0, NUM_SAMPLES)
250 print("FAIL: get_adc with out-of-range sample should have raised an exception")
251 return 1
252 except Exception:
253 pass
254
255 print("PASS: out-of-range ADC indices raise exceptions as expected")
256 return 0
257
258
259def main() -> int:
260 tests = [
261 test_construction_and_size,
262 test_static_members,
263 test_bytes_roundtrip,
264 test_less_than_operator,
265 test_timestamp,
266 test_channel,
267 test_daqheader_accessible,
268 test_set_geoid,
269 test_header_properties,
270 test_adc_single,
271 test_adc_max_value,
272 test_adc_independence,
273 test_adc_all_channels_one_sample,
274 test_adc_out_of_range,
275 ]
276
277 failures = 0
278 for test in tests:
279 failures += test()
280
281 print()
282 if failures == 0:
283 print("All TDEEthFrame Python binding tests passed")
284 else:
285 print(f"{failures} TDEEthFrame Python binding test(s) FAILED")
286 return failures
287
288
289if __name__ == "__main__":
290 sys.exit(main())