gondola_core/monitoring/heartbeats/
master_trigger_hb.rs1use 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 n_events : u64,
13 pub evq_num_events_last : u64,
14 pub evq_num_events_avg : u64,
15 pub n_ev_unsent : u64,
16 pub n_ev_missed : u64,
17 pub trate : u64,
18 pub lost_trate : u64,
19 pub prescale_track : f32,
21 pub prescale_gaps : f32,
22 pub timestamp : u64,
24}
25
26impl MasterTriggerHB {
27 pub fn new() -> Self {
28 Self {
29 version : ProtocolVersion::Unknown,
30 total_elapsed : 0,
31 n_events : 0,
32 evq_num_events_last : 0,
33 evq_num_events_avg : 0,
34 n_ev_unsent : 0,
35 n_ev_missed : 0,
36 trate : 0,
37 lost_trate : 0,
38 prescale_track : 0.0,
40 prescale_gaps : 0.0,
41 timestamp : 0,
42 }
43 }
44
45 pub fn get_sent_packet_rate(&self) -> f64 {
46 if self.total_elapsed > 0 {
47 return self.n_events as f64 / self.total_elapsed as f64;
48 }
49 0.0
50 }
51
52 pub fn get_prescale_track(&self) -> f64 {
54 if self.version == ProtocolVersion::Unknown {
55 error!("Prescale not available for protocol version < V1!");
56 return 0.0;
57 }
58 return self.prescale_track as f64
59 }
60
61 pub fn get_prescale_gaps(&self) -> f64 {
63 if self.version == ProtocolVersion::Unknown {
64 error!("Prescale not available for protocol version < V1!");
65 return 0.0;
66 }
67 return self.prescale_gaps as f64
68 }
69
70
71 pub fn pretty_print(&self) -> String {
72 let mut repr = format!("<MasterTriggerHBs (version : {})", self.version);
73 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} "));
74 repr += &(format!("\n MET (Mission Elapsed Time) : {:.1} sec", self.total_elapsed));
75 repr += &(format!("\n Num. recorded Events : {}", self.n_events));
76 repr += &(format!("\n Last MTB EVQ size : {}", self.evq_num_events_last));
77 repr += &(format!("\n Avg. MTB EVQ size (per 30s ): {:.2}", self.evq_num_events_avg));
78 repr += &(format!("\n trigger rate, recorded: : {:.2} Hz", self.n_events as f64 / self.total_elapsed as f64));
79 repr += &(format!("\n trigger rate, from register : {:.2} Hz", self.trate));
80 repr += &(format!("\n lost trg rate, from register: {:.2} Hz", self.lost_trate));
81 if self.n_ev_unsent > 0 {
82 repr += &(format!("\n Num. sent errors : {}", self.n_ev_unsent).bold());
83 }
84 if self.n_ev_missed > 0 {
85 repr += &(format!("\n Num. missed events : {}", self.n_ev_missed).bold());
86 }
87 if self.version != ProtocolVersion::Unknown {
88 repr += &(format!("\n Prescale, prim. ('GAPS') trg : {:.4}", self.prescale_gaps));
89 repr += &(format!("\n Prescale sec. ('Track') trg : {:.4}", self.prescale_track));
90 }
91 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} "));
92 repr
93 }
94}
95
96impl Default for MasterTriggerHB {
97 fn default () -> Self {
98 Self::new()
99 }
100}
101
102impl TofPackable for MasterTriggerHB {
103 const TOF_PACKET_TYPE : TofPacketType = TofPacketType::MasterTriggerHB;
104}
105
106impl Serialization for MasterTriggerHB {
107 const HEAD : u16 = 0xAAAA;
108 const TAIL : u16 = 0x5555;
109 const SIZE : usize = 68;
110
111 fn from_bytestream(stream :&Vec<u8>,
112 pos :&mut usize)
113 -> Result<Self, SerializationError>{
114 Self::verify_fixed(stream, pos)?;
115 let mut hb = MasterTriggerHB::new();
116 hb.total_elapsed = parse_u64(stream, pos);
117 hb.n_events = parse_u64(stream, pos);
118 hb.evq_num_events_last = parse_u64(stream, pos);
119 hb.evq_num_events_avg = parse_u64(stream, pos);
120 hb.n_ev_unsent = parse_u64(stream, pos);
121 hb.n_ev_missed = parse_u64(stream, pos);
122 hb.version = ProtocolVersion::from(parse_u8(stream, pos) as u8);
133 *pos += 1;
134 hb.trate = parse_u16(stream, pos) as u64;
135 hb.prescale_track = parse_f32(stream, pos);
136 *pos += 2;
137 hb.lost_trate = parse_u16(stream, pos) as u64;
138 hb.prescale_gaps = parse_f32(stream, pos);
139 if hb.version == ProtocolVersion::Unknown {
140 hb.prescale_gaps = 0.0;
141 hb.prescale_track = 0.0
142 }
143 *pos += 2;
144 Ok(hb)
145 }
146
147 fn to_bytestream(&self) -> Vec<u8> {
148 let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
149 bs.extend_from_slice(&Self::HEAD.to_le_bytes());
150 bs.extend_from_slice(&self.total_elapsed.to_le_bytes());
151 bs.extend_from_slice(&self.n_events.to_le_bytes());
152 bs.extend_from_slice(&self.evq_num_events_last.to_le_bytes());
153 bs.extend_from_slice(&self.evq_num_events_avg.to_le_bytes());
154 bs.extend_from_slice(&self.n_ev_unsent.to_le_bytes());
155 bs.extend_from_slice(&self.n_ev_missed.to_le_bytes());
156 bs.push(self.version as u8);
157 bs.push(0u8);
158 let short_trate = (self.trate & 0x0000000000ffffff) as u16;
159 bs.extend_from_slice(&short_trate.to_le_bytes());
160 bs.extend_from_slice(&self.prescale_track.to_le_bytes());
161 let short_lrate = (self.lost_trate & 0x0000000000ffffff) as u16;
162 bs.extend_from_slice(&short_lrate.to_le_bytes());
164 bs.extend_from_slice(&short_lrate.to_le_bytes());
165 bs.extend_from_slice(&self.prescale_gaps.to_le_bytes());
166 bs.extend_from_slice(&Self::TAIL.to_le_bytes());
176 bs
177 }
178}
179
180#[cfg(feature = "random")]
181impl FromRandom for MasterTriggerHB {
182 fn from_random() -> Self {
183 let mut hb = Self::new();
184 let mut rng = rand::rng();
185 hb.total_elapsed = rng.random::<u64>();
186 hb.n_events = rng.random::<u64>();
187 hb.evq_num_events_last = rng.random::<u64>();
188 hb.evq_num_events_avg = rng.random::<u64>();
189 hb.n_ev_unsent = rng.random::<u64>();
190 hb.n_ev_missed = rng.random::<u64>();
191 hb.trate = rng.random::<u16>() as u64;
192 hb.lost_trate = rng.random::<u16>() as u64;
193 hb.version = ProtocolVersion::from_random();
194 if hb.version != ProtocolVersion::Unknown {
195 hb.prescale_gaps = rng.random::<f32>();
196 hb.prescale_track = rng.random::<f32>();
197 }
198 hb
199 }
200}
201
202impl fmt::Display for MasterTriggerHB {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 let repr = self.pretty_print();
205 write!(f, "{}", repr)
206 }
207}
208
209impl MoniData for MasterTriggerHB {
210 fn get_board_id(&self) -> u8 {
211 0
212 }
213
214 fn get_timestamp(&self) -> u64 {
215 self.timestamp
216 }
217
218 fn set_timestamp(&mut self, ts : u64) {
219 self.timestamp = ts;
220 }
221
222 fn get(&self, varname : &str) -> Option<f32> {
224 match varname {
225 "total_elapsed" => Some(self.total_elapsed as f32),
226 "n_events" => Some(self.n_events as f32),
227 "evq_num_events_last" => Some(self.evq_num_events_last as f32),
228 "evq_num_events_avg" => Some(self.evq_num_events_avg as f32),
229 "n_ev_unsent" => Some(self.n_ev_unsent as f32),
230 "n_ev_missed" => Some(self.n_ev_missed as f32),
231 "trate" => Some(self.trate as f32),
232 "lost_trate" => Some(self.lost_trate as f32),
233 "prescale_track" => Some(self.prescale_track as f32),
234 "prescale_gaps" => Some(self.prescale_gaps as f32),
235 "timestamp" => Some(self.timestamp as f32),
236 _ => None
237 }
238 }
239
240 fn keys() -> Vec<&'static str> {
242 vec!["board_id", "total_elapsed", "n_events",
243 "evq_num_events_last", "evq_num_events_avg", "n_ev_unsent",
244 "n_ev_missed", "trate", "lost_trate", "prescale_track",
245 "prescale_gaps","timestamp"]
246 }
247}
248
249moniseries!(MasterTriggerHBSeries, MasterTriggerHB);
250
251#[cfg(feature="pybindings")]
254#[pymethods]
255impl MasterTriggerHB {
256
257 #[getter]
259 fn get_total_elapsed(&self) -> u64 {
260 self.total_elapsed
261 }
262
263 #[getter]
264 fn get_evq_mum_events_last(&self) -> u64 {
265 self.evq_num_events_last
266 }
267
268 #[getter]
269 fn get_evq_num_events_avg(&self) -> u64 {
270 self.evq_num_events_avg
271 }
272
273 #[getter]
274 fn get_n_ev_unsent(&self) -> u64 {
275 self.n_ev_unsent
276 }
277
278 #[getter]
279 fn get_n_ev_missed(&self) -> u64 {
280 self.n_ev_missed
281 }
282
283 #[getter]
284 fn get_trate(&self) -> u64 {
285 self.trate
286 }
287
288 #[getter]
289 fn get_lost_trate(&self) -> u64 {
290 self.lost_trate
291 }
292
293 #[getter]
294 #[pyo3(name="get_prescale_track")]
295 fn get_prescale_track_py(&self) -> f32 {
296 self.prescale_track
297 }
298
299 #[getter]
300 #[pyo3(name="get_prescale_gaps")]
301 fn get_prescale_gaps_py(&self) -> f32 {
302 self.prescale_gaps
303 }
304
305 #[getter]
306 #[pyo3(name="timestamp")]
307 fn get_timestamp_py(&self) -> u64 {
308 self.timestamp
309 }
310}
311
312#[cfg(feature="pybindings")]
313pythonize_packable!(MasterTriggerHB);
314#[cfg(feature="pybindings")]
315pythonize_monidata!(MasterTriggerHB);
316
317#[cfg(feature="random")]
320#[test]
321fn pack_master_trigger_hb() {
322 for _ in 0..100 {
323 let hb = MasterTriggerHB::from_random();
324 let test : MasterTriggerHB = hb.pack().unpack().unwrap();
325 assert_eq!(hb, test);
326 }
327}
328
329