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