1use crate::prelude::*;
5use colored::Colorize;
6
7#[derive(Debug, Copy, Clone, PartialEq)]
8#[cfg_attr(feature="pybindings", pyclass)]
9pub struct MasterTriggerHB {
10 pub version : ProtocolVersion,
11 pub total_elapsed : u64, pub trigger_type : TriggerType,
13 pub combo_trig_type : TriggerType,
14 pub n_events : u64,
15 pub evq_num_events_last : u64,
16 pub evq_num_events_avg : u64,
17 pub n_ev_unsent : u64,
18 pub n_ev_missed : u64,
19 pub trate : u64,
20 pub lost_trate : u64,
21 pub clock_rate : u64,
22 pub rb_lost_rate : u64,
23 pub prescale_track : f32,
25 pub prescale_gaps : f32,
26 pub tiu_ignore_deadtime : bool,
27 pub tiu_timeout_cnt : u64,
28 pub tiu_busy_rate : u16,
29 pub trg_lost_trg_rate : u16,
30 pub gaps_blocked_rate : u16,
31 pub track_blocked_rate : u16,
32 pub any_blocked_rate : u16,
33 pub trkctrl_blocked_rate: u16,
34 pub trkumbctrl_blocked : u16,
35 pub prescale_bypass : bool
36}
37
38impl MasterTriggerHB {
39 pub fn new() -> Self {
40 Self {
41 version : ProtocolVersion::Unknown,
42 total_elapsed : 0,
43 trigger_type : TriggerType::Unknown,
44 combo_trig_type : TriggerType::Unknown,
45 n_events : 0,
46 evq_num_events_last : 0,
47 evq_num_events_avg : 0,
48 n_ev_unsent : 0,
49 n_ev_missed : 0,
50 trate : 0,
51 lost_trate : 0,
52 clock_rate : 0,
53 rb_lost_rate : 0,
54 prescale_track : 0.0,
56 prescale_gaps : 0.0,
57 tiu_ignore_deadtime : false,
58 tiu_timeout_cnt : 0,
59 tiu_busy_rate : 0,
60 trg_lost_trg_rate : 0,
61 gaps_blocked_rate : 0,
62 track_blocked_rate : 0,
63 any_blocked_rate : 0,
64 trkctrl_blocked_rate: 0,
65 trkumbctrl_blocked : 0,
66 prescale_bypass : false
67 }
68 }
69
70 pub fn get_sent_packet_rate(&self) -> f64 {
71 if self.total_elapsed > 0 {
72 return self.n_events as f64 / self.total_elapsed as f64;
73 }
74 0.0
75 }
76
77 pub fn get_prescale_track(&self) -> f64 {
79 if self.version == ProtocolVersion::Unknown {
80 error!("Prescale not available for protocol version < V1!");
81 return 0.0;
82 }
83 return self.prescale_track as f64
84 }
85
86 pub fn get_prescale_gaps(&self) -> f64 {
88 if self.version == ProtocolVersion::Unknown {
89 error!("Prescale not available for protocol version < V1!");
90 return 0.0;
91 }
92 return self.prescale_gaps as f64
93 }
94
95
96 pub fn pretty_print(&self) -> String {
97 let mut repr = format!("<MasterTriggerHBs (version : {})", self.version);
98 repr += &(format!("\n \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} MTB HEARTBEAT \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} "));
99 repr += &(format!("\n MET (Mission Elapsed Time) : {:.1} sec", self.total_elapsed));
100 repr += &(format!("\n Primary trigger type : {}", self.trigger_type));
101 repr += &(format!("\n Secondary trigger type : {}", self.combo_trig_type));
102 if self.version != ProtocolVersion::Unknown {
103 repr += &(format!("\n Primary trigger prescale : {:.4}", self.prescale_gaps));
104 repr += &(format!("\n Secondary trigger prescale : {:.4}", self.prescale_track));
105 repr += &(format!("\n Bypass presecale? : {}", self.prescale_bypass));
106 }
107 repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
108 repr += &(format!("\n total trigger rate, recorded: : {:.2} Hz", self.n_events as f64 / self.total_elapsed as f64));
109 repr += &(format!("\n total trigger rate, from register : {:.2} Hz", self.trate));
110 repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
111 repr += &(format!("\n lost total trg rate, from register: {:.2} Hz", self.lost_trate));
112 repr += &(format!("\n trigger lost rate, from register : {:.2} Hz", self.trg_lost_trg_rate));
113 repr += &(format!("\n RB lost rate, from register : {:.2} Hz", self.rb_lost_rate));
114 repr += &(format!("\n TIU lost rate, from register : {:.2} HZ", self.tiu_busy_rate));
115 repr += &(format!("\n"));
116 match self.trigger_type {
117 TriggerType::Gaps => {
118 repr += &(format!("\n GAPS trigger blocked rate : {}", self.gaps_blocked_rate));
119 }
120 TriggerType::Track => {
121 repr += &(format!("\n Track trigger blocked rate : {}", self.track_blocked_rate));
122 }
123 TriggerType::Any => {
124 repr += &(format!("\n Any trigger blocked rate : {}", self.any_blocked_rate));
125 }
126 TriggerType::TrackCentral => {
127 repr += &(format!("\n Track central blocked rate : {}", self.trkctrl_blocked_rate));
128 }
129 TriggerType::TrackUmbCentral => {
130 repr += &(format!("\n TrackUmbCentral blocked rate : {}", self.trkumbctrl_blocked));
131 }
132 _ => {
133 repr += &(format!("\n register not implemented for {} trigger blocked rate", self.trigger_type));
134 }
135 }
136
137 repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
138 repr += &(format!("\n Num. recorded Events : {}", self.n_events));
139 repr += &(format!("\n MTB clock rate : {}", self.clock_rate));
140
141 repr += &(format!("\n"));
142 repr += &(format!("\n Using TOF fixed deadtime? : {}", self.tiu_ignore_deadtime));
143 repr += &(format!("\n Fixed deadtime (*10ns) : {}", self.tiu_timeout_cnt));
144
145 repr += &(format!("\n \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504} \u{2504}"));
146 repr += &(format!("\n Last MTB EVQ size : {}", self.evq_num_events_last));
147 repr += &(format!("\n Avg. MTB EVQ size (per 30s ): {:.2}", self.evq_num_events_avg));
148 if self.n_ev_unsent > 0 {
149 repr += &(format!("\n Num. sent errors : {}", self.n_ev_unsent).bold());
150 }
151 if self.n_ev_missed > 0 {
152 repr += &(format!("\n Num. missed events : {}", self.n_ev_missed).bold());
153 }
154 repr += &(format!("\n \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} END HEARTBEAT \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} \u{1FA90} "));
155 repr
156 }
157}
158
159impl Default for MasterTriggerHB {
160 fn default () -> Self {
161 Self::new()
162 }
163}
164
165impl TofPackable for MasterTriggerHB {
166 const TOF_PACKET_TYPE : TofPacketType = TofPacketType::MasterTriggerHB;
167}
168
169impl Serialization for MasterTriggerHB {
170 const HEAD : u16 = 0xAAAA;
171 const TAIL : u16 = 0x5555;
172 const SIZE : usize = 111;
173
174 fn from_bytestream(stream :&Vec<u8>,
175 pos :&mut usize)
176 -> Result<Self, SerializationError>{
177 Self::verify_fixed(stream, pos)?;
178 let mut hb = MasterTriggerHB::new();
179 hb.version = ProtocolVersion::from(parse_u8(stream, pos) as u8);
180 hb.total_elapsed = parse_u64(stream, pos);
181 hb.trigger_type = TriggerType::from(parse_u8(stream, pos) as u8);
182 hb.combo_trig_type = TriggerType::from(parse_u8(stream, pos) as u8);
183 hb.n_events = parse_u64(stream, pos);
184 hb.evq_num_events_last = parse_u64(stream, pos);
185 hb.evq_num_events_avg = parse_u64(stream, pos);
186 hb.n_ev_unsent = parse_u64(stream, pos);
187 hb.n_ev_missed = parse_u64(stream, pos);
188 hb.trate = parse_u64(stream, pos);
189 hb.lost_trate = parse_u64(stream, pos);
190 hb.clock_rate = parse_u64(stream, pos);
191 hb.rb_lost_rate = parse_u64(stream, pos);
192 hb.prescale_track = parse_f32(stream, pos);
193 hb.prescale_gaps = parse_f32(stream, pos);
194 hb.tiu_ignore_deadtime = parse_bool(stream, pos);
200 hb.tiu_timeout_cnt = parse_u64(stream, pos);
201 hb.tiu_busy_rate = parse_u16(stream, pos);
202 hb.trg_lost_trg_rate = parse_u16(stream, pos);
203 match hb.trigger_type {
204 TriggerType::Gaps => {
205 hb.gaps_blocked_rate = parse_u16(stream, pos);
206 }
207 TriggerType::Track => {
208 hb.track_blocked_rate = parse_u16(stream, pos);
209 }
210 TriggerType::Any => {
211 hb.any_blocked_rate = parse_u16(stream, pos);
212 }
213 TriggerType::TrackCentral => {
214 hb.trkctrl_blocked_rate = parse_u16(stream, pos);
215 }
216 TriggerType::TrackUmbCentral => {
217 hb.trkumbctrl_blocked = parse_u16(stream, pos);
218 }
219 _ => {
220 *pos += 2;
221 }
222 }
223 hb.prescale_bypass = parse_bool(stream, pos);
224 *pos += 2;
225 Ok(hb)
226 }
227
228 fn to_bytestream(&self) -> Vec<u8> {
229 let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
230 bs.extend_from_slice(&Self::HEAD.to_le_bytes());
231 bs.push(self.version as u8);
232 bs.extend_from_slice(&self.total_elapsed.to_le_bytes());
233 bs.extend_from_slice(&(self.trigger_type as u8).to_le_bytes());
234 bs.extend_from_slice(&(self.combo_trig_type as u8).to_le_bytes());
235 bs.extend_from_slice(&self.n_events.to_le_bytes());
236 bs.extend_from_slice(&self.evq_num_events_last.to_le_bytes());
237 bs.extend_from_slice(&self.evq_num_events_avg.to_le_bytes());
238 bs.extend_from_slice(&self.n_ev_unsent.to_le_bytes());
239 bs.extend_from_slice(&self.n_ev_missed.to_le_bytes());
240 bs.extend_from_slice(&self.trate.to_le_bytes());
241 bs.extend_from_slice(&self.lost_trate.to_le_bytes());
242 bs.extend_from_slice(&self.clock_rate.to_le_bytes());
243 bs.extend_from_slice(&self.rb_lost_rate.to_le_bytes());
244 bs.extend_from_slice(&self.prescale_track.to_le_bytes());
245 bs.extend_from_slice(&self.prescale_gaps.to_le_bytes());
246 bs.extend_from_slice(&(self.tiu_ignore_deadtime as u8).to_le_bytes());
247 bs.extend_from_slice(&self.tiu_timeout_cnt.to_le_bytes());
248 bs.extend_from_slice(&self.tiu_busy_rate.to_le_bytes());
249 bs.extend_from_slice(&self.trg_lost_trg_rate.to_le_bytes());
250 match self.trigger_type {
251 TriggerType::Gaps => {
252 bs.extend_from_slice(&self.gaps_blocked_rate.to_le_bytes());
253 }
254 TriggerType::Track => {
255 bs.extend_from_slice(&self.track_blocked_rate.to_le_bytes());
256 }
257 TriggerType::Any => {
258 bs.extend_from_slice(&self.any_blocked_rate.to_le_bytes());
259 }
260 TriggerType::TrackCentral => {
261 bs.extend_from_slice(&self.trkctrl_blocked_rate.to_le_bytes());
262 }
263 TriggerType::TrackUmbCentral => {
264 bs.extend_from_slice(&self.trkumbctrl_blocked.to_le_bytes());
265 }
266 _ => {
267 bs.extend_from_slice(&[0u8; 2]);
268 }
269 }
270 bs.extend_from_slice(&(self.prescale_bypass as u8).to_le_bytes());
271 bs.extend_from_slice(&Self::TAIL.to_le_bytes());
272 bs
273 }
274}
275
276#[cfg(feature = "random")]
277impl FromRandom for MasterTriggerHB {
278 fn from_random() -> Self {
279 let mut hb = Self::new();
280 let mut rng = rand::rng();
281 hb.version = ProtocolVersion::from_random();
282 hb.total_elapsed = rng.random::<u64>();
283 hb.trigger_type = TriggerType::from_random();
284 hb.combo_trig_type = TriggerType::from_random();
285 hb.n_events = rng.random::<u64>();
286 hb.evq_num_events_last = rng.random::<u64>();
287 hb.evq_num_events_avg = rng.random::<u64>();
288 hb.n_ev_unsent = rng.random::<u64>();
289 hb.n_ev_missed = rng.random::<u64>();
290 hb.trate = rng.random::<u16>() as u64;
291 hb.lost_trate = rng.random::<u16>() as u64;
292 hb.clock_rate = rng.random::<u64>();
293 hb.rb_lost_rate = rng.random::<u16>() as u64;
294 hb.prescale_track = rng.random::<f32>();
295 hb.prescale_gaps = rng.random::<f32>();
296 hb.tiu_ignore_deadtime = rng.random::<bool>();
297 hb.tiu_timeout_cnt = rng.random::<u64>();
298 hb.tiu_busy_rate = rng.random::<u16>();
299 hb.trg_lost_trg_rate = rng.random::<u16>();
300 match hb.trigger_type {
301 TriggerType::Gaps => {
302 hb.gaps_blocked_rate = rng.random::<u16>();
303 }
304 TriggerType::Track => {
305 hb.track_blocked_rate = rng.random::<u16>();
306 }
307 TriggerType::Any => {
308 hb.any_blocked_rate = rng.random::<u16>();
309 }
310 TriggerType::TrackCentral => {
311 hb.trkctrl_blocked_rate = rng.random::<u16>();
312 }
313 TriggerType::TrackUmbCentral => {
314 hb.trkumbctrl_blocked = rng.random::<u16>();
315 }
316 _ => {}
317 }
318 hb.prescale_bypass = rng.random::<bool>();
319 hb
320 }
321}
322
323impl fmt::Display for MasterTriggerHB {
324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325 let repr = self.pretty_print();
326 write!(f, "{}", repr)
327 }
328}
329
330impl MoniData for MasterTriggerHB {
331 fn get_board_id(&self) -> u8 {
332 0
333 }
334
335 fn get_timestamp(&self) -> u64 {
336 self.total_elapsed
337 }
338 fn get(&self, varname : &str) -> Option<f32> {
350 match varname {
351 "total_elapsed" => Some(self.total_elapsed as f32),
352 "n_events" => Some(self.n_events as f32),
353 "evq_num_events_last" => Some(self.evq_num_events_last as f32),
354 "evq_num_events_avg" => Some(self.evq_num_events_avg as f32),
355 "n_ev_unsent" => Some(self.n_ev_unsent as f32),
356 "n_ev_missed" => Some(self.n_ev_missed as f32),
357 "trate" => Some(self.trate as f32),
358 "lost_trate" => Some(self.lost_trate as f32),
359 "prescale_track" => Some(self.prescale_track as f32),
360 "prescale_gaps" => Some(self.prescale_gaps as f32),
361 "clock_rate" => Some(self.clock_rate as f32),
362 "rb_lost_rate" => Some(self.rb_lost_rate as f32),
363 "tiu_timeout_cnt" => Some(self.tiu_timeout_cnt as f32),
364 "tiu_busy_rate" => Some(self.tiu_busy_rate as f32),
365 "trg_lost_trg_rate" => Some(self.trg_lost_trg_rate as f32),
366 "prescale_bypass" => Some(self.prescale_bypass as u8 as f32),
367 "tiu_ignore_deadtime" => Some(self.tiu_ignore_deadtime as u8 as f32),
368 "trigger_type" => Some(self.trigger_type.to_u8() as f32),
369 "combo_trig_type" => Some(self.combo_trig_type.to_u8() as f32),
370 "gaps_blocked_rate" => Some(self.gaps_blocked_rate as f32),
371 "track_blocked_rate" => Some(self.track_blocked_rate as f32),
372 "any_blocked_rate" => Some(self.any_blocked_rate as f32),
373 "trkctrl_blocked_rate"=> Some(self.trkctrl_blocked_rate as f32),
374 "trkumbctrl_blocked" => Some(self.trkumbctrl_blocked as f32),
375 _ => None
377 }
378 }
379
380 fn keys() -> Vec<&'static str> {
382 vec!["total_elapsed", "trigger_type", "combo_trig_type", "n_events",
383 "evq_num_events_last", "evq_num_events_avg", "n_ev_unsent",
384 "n_ev_missed", "trate", "lost_trate","clock_rate", "rb_lost_rate", "prescale_track",
385 "prescale_gaps", "tiu_ignore_deadtime", "tiu_timeout_cnt", "tiu_busy_rate", "trg_lost_trg_rate",
386 "gaps_blocked_rate", "track_blocked_rate", "any_blocked_rate", "trkctrl_blocked_rate",
387 "trkumbctrl_blocked", "prescale_bypass"]
388 }
389}
390
391moniseries!(MasterTriggerHBSeries, MasterTriggerHB);
392
393#[cfg(feature="pybindings")]
396#[pymethods]
397impl MasterTriggerHB {
398
399 #[getter]
402 fn get_clock_rate(&self) -> u64 {
403 self.clock_rate
404 }
405 #[getter]
406 fn get_trigger_type(&self) -> TriggerType {
407 self.trigger_type
408 }
409
410 #[getter]
411 fn get_combo_trig_type(&self) -> TriggerType {
412 self.combo_trig_type
413 }
414 #[getter]
415 fn get_rb_lost_rate(&self) -> u64 {
416 self.rb_lost_rate
417 }
418
419 #[getter]
420 fn get_tiu_ignore_deadtime(&self) -> bool {
421 self.tiu_ignore_deadtime
422 }
423 #[getter]
424 fn get_tiu_timeout_cnt(&self) -> u64 {
425 self.tiu_timeout_cnt
426 }
427 #[getter]
428 fn get_tiu_busy_rate(&self) -> u16 {
429 self.tiu_busy_rate
430 }
431 #[getter]
432 fn get_trg_lost_trg_rate(&self) -> u16 {
433 self.trg_lost_trg_rate
434 }
435 #[getter]
436 fn get_gaps_blocked_rate(&self) -> u16 {
437 self.gaps_blocked_rate
438 }
439
440 #[getter]
441 fn get_track_blocked_rate(&self) -> u16 {
442 self.track_blocked_rate
443 }
444
445 #[getter]
446 fn get_any_blocked_rate(&self) -> u16 {
447 self.any_blocked_rate
448 }
449 #[getter]
450 fn get_track_central_blocked_rate(&self) -> u16 {
451 self.trkctrl_blocked_rate
452 }
453 #[getter]
454 fn get_track_umb_central_blocked_rate(&self) -> u16 {
455 self.trkumbctrl_blocked
456 }
457 #[getter]
458 fn get_prescale_bypass(&self) -> bool {
459 self.prescale_bypass
460 }
461 #[getter]
462 fn get_total_elapsed(&self) -> u64 {
463 self.total_elapsed
464 }
465
466 #[getter]
467 fn get_evq_mum_events_last(&self) -> u64 {
468 self.evq_num_events_last
469 }
470
471 #[getter]
472 fn get_evq_num_events_avg(&self) -> u64 {
473 self.evq_num_events_avg
474 }
475
476 #[getter]
477 fn get_n_ev_unsent(&self) -> u64 {
478 self.n_ev_unsent
479 }
480
481 #[getter]
482 fn get_n_ev_missed(&self) -> u64 {
483 self.n_ev_missed
484 }
485
486 #[getter]
487 fn get_trate(&self) -> u64 {
488 self.trate
489 }
490
491 #[getter]
492 fn get_lost_trate(&self) -> u64 {
493 self.lost_trate
494 }
495
496 #[getter]
497 #[pyo3(name="get_prescale_track")]
498 fn get_prescale_track_py(&self) -> f32 {
499 self.prescale_track
500 }
501
502 #[getter]
503 #[pyo3(name="get_prescale_gaps")]
504 fn get_prescale_gaps_py(&self) -> f32 {
505 self.prescale_gaps
506 }
507
508 }
516
517#[cfg(feature="pybindings")]
518pythonize_packable!(MasterTriggerHB);
519#[cfg(feature="pybindings")]
520pythonize_monidata!(MasterTriggerHB);
521
522#[cfg(feature="random")]
525#[test]
526fn pack_master_trigger_hb() {
527 for _ in 0..100 {
528 let hb = MasterTriggerHB::from_random();
529 let test : MasterTriggerHB = hb.pack().unpack().unwrap();
530 assert_eq!(hb, test);
531 }
532}
533
534