1use crate::prelude::*;
5use colored::Colorize;
6
7#[cfg_attr(feature="pybindings",pyclass)]
12#[derive(Debug, Copy, Clone, PartialEq)]
13pub struct RBEventHeader {
14 pub rb_id : u8 ,
18 pub event_id : u32 ,
21 pub stop_cell : u16 ,
24 pub pid_ch12 : u8,
26 pub pid_ch34 : u8,
28 pub pid_ch56 : u8,
30 pub pid_ch78 : u8,
32 pub pid_ch_order : u8,
34 pub rsvd1 : u8,
36 pub rsvd2 : u8,
38 pub rsvd3 : u8,
40 pub fpga_temp : u16,
43 pub drs_deadtime : u16,
46 pub timestamp32 : u32,
47 pub timestamp16 : u16,
48 pub deadtime_instead_temp : bool,
51 pub status_byte : u8,
54 pub channel_mask : u16,
64}
65
66impl RBEventHeader {
67
68 pub fn new() -> Self {
69 Self {
70 rb_id : 0,
71 status_byte : 0,
72 event_id : 0,
73 channel_mask : 0,
74 stop_cell : 0,
75 pid_ch12 : 0,
76 pid_ch34 : 0,
77 pid_ch56 : 0,
78 pid_ch78 : 0,
79 pid_ch_order : 0,
80 rsvd1 : 0,
81 rsvd2 : 0,
82 rsvd3 : 0,
83 fpga_temp : 0,
84 drs_deadtime : 0,
85 timestamp32 : 0,
86 timestamp16 : 0,
87 deadtime_instead_temp : false,
88 }
89 }
90
91 pub fn set_channel_mask(&mut self, channel_mask : u16) {
96 if self.deadtime_instead_temp {
97 self.channel_mask = 2u16.pow(15) | channel_mask;
98 } else {
99 self.channel_mask = channel_mask;
100 }
101 }
102
103 pub fn get_channel_mask(&self) -> u16 {
107 self.channel_mask & 0x1ff
108 }
109
110 pub fn parse_channel_mask(ch_mask : u16) -> (bool, u16) {
116 let channel_mask : u16;
117 let deadtime_instead_temp : bool
118 = ch_mask >> 15 == 1;
119 channel_mask = ch_mask & 0x1ff;
120 (deadtime_instead_temp, channel_mask)
121 }
122
123 pub fn extract_eventid_from_rbheader(stream :&Vec<u8>) -> u32 {
125 let event_id = parse_u32(stream, &mut 3); event_id
129 }
130
131 pub fn is_event_fragment(&self) -> bool {
132 self.status_byte & 1 > 0
133 }
134
135 pub fn drs_lost_trigger(&self) -> bool {
136 (self.status_byte >> 1) & 1 > 0
137 }
138
139 pub fn lost_lock(&self) -> bool {
140 (self.status_byte >> 2) & 1 > 0
141 }
142
143 pub fn lost_lock_last_sec(&self) -> bool {
144 (self.status_byte >> 3) & 1 > 0
145 }
146
147 pub fn is_locked(&self) -> bool {
148 !self.lost_lock()
149 }
150
151 pub fn is_locked_last_sec(&self) -> bool {
152 !self.lost_lock_last_sec()
153 }
154
155 pub fn parse_status(&mut self, status_bytes : u16) {
157 self.status_byte = (status_bytes & 0xf) as u8;
159 self.fpga_temp = status_bytes >> 4;
160 }
161
162 pub fn get_fpga_temp(&self) -> f32 {
164 let zynq_temp = (((self.fpga_temp & 4095) as f32 * 503.975) / 4096.0) - 273.15;
165 zynq_temp
166 }
167
168 pub fn has_ch9(&self) -> bool {
171 self.channel_mask & 256 > 0
172 }
173
174 pub fn get_rbpaddleid(&self) -> RBPaddleID {
175 let mut pid = RBPaddleID::new();
176 pid.paddle_12 = self.pid_ch12;
177 pid.paddle_34 = self.pid_ch34;
178 pid.paddle_56 = self.pid_ch56;
179 pid.paddle_78 = self.pid_ch78;
180 pid.channel_order = self.pid_ch_order;
181 pid
182 }
183
184 pub fn set_rbpaddleid(&mut self, pid : &RBPaddleID) {
185 self.pid_ch12 = pid.paddle_12;
186 self.pid_ch34 = pid.paddle_34;
187 self.pid_ch56 = pid.paddle_56;
188 self.pid_ch78 = pid.paddle_78;
189 self.pid_ch_order = pid.channel_order;
190 }
191
192 pub fn get_channels(&self) -> Vec<u8> {
199 let mut channels = Vec::<u8>::with_capacity(8);
200 for k in 0..9 {
201 if self.channel_mask & (1 << k) > 0 {
202 channels.push(k);
203 }
204 }
205 channels
206 }
207
208 pub fn get_active_paddles(&self) -> Vec<(u8,bool)> {
210 let mut active_paddles = Vec::<(u8,bool)>::new();
213 let active_channels = self.get_channels();
214 let pid = self.get_rbpaddleid();
215 let mut ch0_pair_done = false;
216 let mut ch2_pair_done = false;
217 let mut ch4_pair_done = false;
218 let mut ch6_pair_done = false;
219 for ch in active_channels {
220 if (ch == 0 || ch == 1) && !ch0_pair_done {
221 active_paddles.push(pid.get_paddle_id(ch));
222 ch0_pair_done = true;
223 }
224 if (ch == 2 || ch == 3) && !ch2_pair_done {
225 active_paddles.push(pid.get_paddle_id(ch));
226 ch2_pair_done = true;
227 }
228 if (ch == 4 || ch == 5) && !ch4_pair_done {
229 active_paddles.push(pid.get_paddle_id(ch));
230 ch4_pair_done = true;
231 }
232 if (ch == 6 || ch == 7) && !ch6_pair_done {
233 active_paddles.push(pid.get_paddle_id(ch));
234 ch6_pair_done = true;
235 }
236 }
237 active_paddles
238 }
239
240 pub fn get_nchan(&self) -> usize {
242 self.get_channels().len()
243 }
244
245 pub fn get_timestamp48(&self) -> u64 {
246 ((self.timestamp16 as u64) << 32) | self.timestamp32 as u64
247 }
248}
249
250impl Default for RBEventHeader {
251 fn default() -> Self {
252 Self::new()
253 }
254}
255
256
257impl fmt::Display for RBEventHeader {
258 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259 let mut repr = String::from("<RBEventHeader:");
260 repr += &(format!("\n RB ID {}",self.rb_id ));
261 repr += &(format!("\n event id {}",self.event_id ));
262 repr += &(format!("\n ch mask {}",self.channel_mask ));
263 repr += &(format!("\n has ch9 {}",self.has_ch9() ));
264 repr += &(format!("\n ch mapping {}",self.get_rbpaddleid() ));
265 if self.deadtime_instead_temp {
266 repr += &(format!("\n DRS deadtime : {:.2}", self.drs_deadtime));
267 } else {
268 repr += &(format!("\n FPGA T [\u{00B0}C] : {:.2}", self.get_fpga_temp()));
269 }
270 repr += &(format!("\n timestamp32 {}", self.timestamp32 ));
271 repr += &(format!("\n timestamp16 {}", self.timestamp16 ));
272 repr += &(format!("\n |-> timestamp48 {}", self.get_timestamp48() ));
273 repr += &(format!("\n stop cell {}", self.stop_cell ));
274 let mut perfect = true;
275 if self.drs_lost_trigger() {
276 repr += &"\n !! DRS4 REPORTS LOST TRIGGER!".red().bold();
277 perfect = false;
278 }
279 if self.is_event_fragment() {
280 repr += &"\n !! EVENT FRAGMENT!".red().bold();
281 perfect = false;
282 }
283 if self.lost_lock() {
284 repr += &"\n !! RB CLOCK IS NOT LOCKED!".yellow().bold();
285 perfect = false;
286 }
287 if self.lost_lock_last_sec() {
288 repr += &"\n !! RB CLOCK HAS LOST ITS LOCK WITHIN THE LAST SECOND!".yellow().bold();
289 perfect = false;
290 }
291 if perfect {
292 repr += &"\n -- locked: YES, locked last second; YES, no event fragemnet, and no lost trigger!".green();
293 }
294 repr += ">";
295 write!(f, "{}", repr)
296 }
297}
298
299impl Serialization for RBEventHeader {
300
301 const HEAD : u16 = 0xAAAA;
302 const TAIL : u16 = 0x5555;
303 const SIZE : usize = 30; fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
306 -> Result<Self, SerializationError> {
307 let mut header = Self::new();
308 Self::verify_fixed(stream, pos)?;
309 header.rb_id = parse_u8 (stream, pos);
310 header.event_id = parse_u32(stream, pos);
311 let ch_mask = parse_u16(stream, pos);
312 let (deadtime_instead_temp, channel_mask)
313 = Self::parse_channel_mask(ch_mask);
314 header.deadtime_instead_temp = deadtime_instead_temp;
315 header.set_channel_mask(channel_mask);
316 header.status_byte = parse_u8 (stream, pos);
317 header.stop_cell = parse_u16(stream, pos);
318 header.pid_ch12 = parse_u8(stream, pos);
319 header.pid_ch34 = parse_u8(stream, pos);
320 header.pid_ch56 = parse_u8(stream, pos);
321 header.pid_ch78 = parse_u8(stream, pos);
322 header.pid_ch_order = parse_u8(stream, pos);
323 header.rsvd1 = parse_u8(stream, pos);
324 header.rsvd2 = parse_u8(stream, pos);
325 header.rsvd3 = parse_u8(stream, pos);
326 if deadtime_instead_temp {
327 header.drs_deadtime = parse_u16(stream, pos);
328 } else {
329 header.fpga_temp = parse_u16(stream, pos);
330 }
331 header.timestamp32 = parse_u32(stream, pos);
332 header.timestamp16 = parse_u16(stream, pos);
333 *pos += 2; Ok(header)
335 }
336
337
338 fn to_bytestream(&self) -> Vec<u8> {
339 let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
340 stream.extend_from_slice(&Self::HEAD.to_le_bytes());
341 stream.extend_from_slice(&self.rb_id .to_le_bytes());
342 stream.extend_from_slice(&self.event_id .to_le_bytes());
343 let ch_mask = ((self.deadtime_instead_temp as u16) << 15) | self.get_channel_mask();
344 stream.extend_from_slice(&ch_mask .to_le_bytes());
345 stream.extend_from_slice(&self.status_byte .to_le_bytes());
346 stream.extend_from_slice(&self.stop_cell .to_le_bytes());
347 stream.push(self.pid_ch12 );
348 stream.push(self.pid_ch34 );
349 stream.push(self.pid_ch56 );
350 stream.push(self.pid_ch78 );
351 stream.push(self.pid_ch_order);
352 stream.push(self.rsvd1 );
353 stream.push(self.rsvd2 );
354 stream.push(self.rsvd3 );
355 if self.deadtime_instead_temp {
356 stream.extend_from_slice(&self.drs_deadtime .to_le_bytes());
357 } else {
358 stream.extend_from_slice(&self.fpga_temp .to_le_bytes());
359 }
360 stream.extend_from_slice(&self.timestamp32 .to_le_bytes());
361 stream.extend_from_slice(&self.timestamp16 .to_le_bytes());
362 stream.extend_from_slice(&RBEventHeader::TAIL.to_le_bytes());
363 stream
364 }
365}
366
367#[cfg(feature = "random")]
368impl FromRandom for RBEventHeader {
369
370 fn from_random() -> Self {
371 let mut header = RBEventHeader::new();
372 let mut rng = rand::rng();
373
374 header.rb_id = rng.random::<u8>();
375 header.event_id = rng.random::<u32>();
376 header.status_byte = rng.random::<u8>();
377 header.stop_cell = rng.random::<u16>();
378 header.pid_ch12 = rng.random::<u8>();
379 header.pid_ch34 = rng.random::<u8>();
380 header.pid_ch56 = rng.random::<u8>();
381 header.pid_ch78 = rng.random::<u8>();
382 header.pid_ch_order = rng.random::<u8>();
383 header.rsvd1 = rng.random::<u8>();
384 header.rsvd2 = rng.random::<u8>();
385 header.rsvd3 = rng.random::<u8>();
386 header.deadtime_instead_temp = rng.random::<bool>();
387 if header.deadtime_instead_temp {
388 header.drs_deadtime = rng.random::<u16>();
389 } else {
390 header.fpga_temp = rng.random::<u16>();
391 }
392 let ch_mask = rng.random::<u16>() & 0x1ff;
394 header.set_channel_mask(ch_mask);
395 header.timestamp32 = rng.random::<u32>();
396 header.timestamp16 = rng.random::<u16>();
397 header
398 }
399}
400
401#[cfg(feature="pybindings")]
404#[pymethods]
405impl RBEventHeader {
406
407 #[getter]
408 #[pyo3(name="rb_id")]
409 fn rb_id_py(&self) -> u8 {
410 self.rb_id
411 }
412
413 #[getter]
414 #[pyo3(name="event_id")]
415 fn event_id_py(&self) -> u32 {
416 self.event_id
417 }
418
419 #[getter]
425 #[pyo3(name="channel_mask")]
426 fn channel_mask_py(&self) -> u16 {
427 self.get_channel_mask()
428 }
429
430 #[getter]
431 #[pyo3(name="stop_cell")]
432 fn stop_cell_py(&self) -> u16 {
433 self.stop_cell
434 }
435
436 #[getter]
437 #[pyo3(name="fpga_temp")]
438 fn fpga_temp_py(&self) -> f32 {
439 self.get_fpga_temp()
440 }
441
442 #[getter]
443 #[pyo3(name="drs_deadtime")]
444 fn drs_deadtime_py(&self) -> u16 {
445 self.drs_deadtime
446 }
447
448 #[getter]
449 #[pyo3(name="timestamp32")]
450 fn timestamp32_py(&self) -> u32 {
451 self.timestamp32
452 }
453
454 #[getter]
455 #[pyo3(name="timestamp16")]
456 fn timestamp16_py(&self) -> u16 {
457 self.timestamp16
458 }
459
460 #[pyo3(name="get_channels")]
464 fn get_channels_py(&self) -> Vec<u8> {
465 self.get_channels()
466 }
467
468 #[getter]
469 #[pyo3(name="is_event_fragment")]
470 pub fn is_event_fragment_py(&self) -> bool {
471 self.is_event_fragment()
472 }
473
474 #[getter]
475 #[pyo3(name="drs_lost_trigger")]
476 pub fn drs_lost_trigger_py(&self) -> bool {
477 self.drs_lost_trigger()
478 }
479
480 #[getter]
481 #[pyo3(name="lost_lock")]
482 fn lost_lock_py(&self) -> bool {
483 self.lost_lock()
484 }
485
486 #[getter]
487 #[pyo3(name="lost_lock_last_sec")]
488 fn lost_lock_last_sec_py(&self) -> bool {
489 self.lost_lock_last_sec()
490 }
491
492 #[getter]
493 #[pyo3(name="is_locked")]
494 fn is_locked_py(&self) -> bool {
495 self.is_locked()
496 }
497
498 #[getter]
499 #[pyo3(name="is_locked_last_sec")]
500 fn is_locked_last_sec_py(&self) -> bool {
501 self.is_locked_last_sec()
502 }
503}
504
505#[cfg(feature="pybindings")]
506pythonize!(RBEventHeader);
507
508#[test]
511fn serialization_rbeventheader() {
512 for _ in 0..100 {
513 let mut pos = 0usize;
514 let head = RBEventHeader::from_random();
515 let stream = head.to_bytestream();
517 assert_eq!(stream.len(), RBEventHeader::SIZE);
518 let test = RBEventHeader::from_bytestream(&stream, &mut pos).unwrap();
519 println!("{}", test);
520 assert_eq!(pos, RBEventHeader::SIZE);
521 assert_eq!(head, test);
522 assert_eq!(head.lost_lock() , test.lost_lock());
523 assert_eq!(head.lost_lock_last_sec(), test.lost_lock_last_sec());
524 assert_eq!(head.drs_lost_trigger() , test.drs_lost_trigger());
525 assert_eq!(head, test);
526 }
527}
528