tof_dataclasses/
heartbeats.rs

1//! Heartbeats - regularly (or on demand) sent 
2//! software monitoring data
3//!
4//! This includes heartbeats for different threads
5
6// use std::collections::btree_map::Range;
7use std::fmt;
8use colored::*;
9use crate::serialization::{
10  Serialization,
11  SerializationError,
12  Packable,
13  parse_u8,
14  parse_u16,
15  parse_f32,
16  parse_u64,
17  parse_usize,
18};
19
20use crate::packets::PacketType;
21use crate::version::ProtocolVersion;
22// use std::collections::HashMap;
23
24#[cfg(feature="random")]
25use crate::FromRandom;
26#[cfg(feature="random")]
27use rand::Rng;
28
29/// A very general and concise way 
30/// to report RB activity
31#[derive(Debug, Copy, Clone, PartialEq)]
32pub struct RBPing {
33  /// RB identifier
34  pub rb_id  : u8,
35  /// runtime of liftof-rb
36  pub uptime : u64,
37}
38
39impl RBPing {
40  pub fn new() -> Self {
41    Self {
42      rb_id  : 0,
43      uptime : 0,
44    }
45  }
46}
47
48impl Packable for RBPing {
49  const PACKET_TYPE : PacketType = PacketType::RBPing;
50}
51
52impl Serialization for RBPing {
53  
54  const HEAD : u16 = 0xAAAA;
55  const TAIL : u16 = 0x5555;
56  const SIZE : usize = 13; 
57  
58  fn from_bytestream(stream    : &Vec<u8>, 
59                     pos       : &mut usize) 
60    -> Result<Self, SerializationError>{
61    Self::verify_fixed(stream, pos)?;  
62    let mut rb_ping = RBPing::new();
63    rb_ping.rb_id   = parse_u8(stream, pos);
64    rb_ping.uptime  = parse_u64(stream, pos);
65    *pos += 2;
66    Ok(rb_ping)
67  }
68  
69  fn to_bytestream(&self) -> Vec<u8> {
70    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
71    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
72    bs.extend_from_slice(&self.rb_id.to_le_bytes());
73    bs.extend_from_slice(&self.uptime.to_le_bytes());
74    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
75    bs
76  }
77}
78
79impl Default for RBPing {
80  fn default() -> Self {
81    Self::new()
82  }
83}
84
85#[cfg(feature = "random")]
86impl FromRandom for RBPing {
87  fn from_random() -> Self {
88    let mut rng      = rand::thread_rng();
89    let rb_id  = rng.gen::<u8>();
90    let uptime = rng.gen::<u64>();
91    Self {
92      rb_id,
93      uptime
94    }
95  }
96}
97
98impl fmt::Display for RBPing {
99  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100    //let cc = RBCommand::command_code_to_string(self.command_code);
101    let mut repr = String::from("<RBPing");
102    repr += &(format!("\n  RB ID      : {}", self.rb_id)); 
103    repr += &(format!("\n  Uptime [s] : {}", self.uptime)); 
104    write!(f, "{}", repr)
105  }
106}
107
108#[derive(Debug, Copy, Clone, PartialEq)]
109pub struct HeartBeatDataSink {
110
111  /// mission elapsed time in seconds
112  pub met                : u64,
113  pub n_packets_sent     : u64,
114  pub n_packets_incoming : u64,
115  /// bytes written to disk
116  pub n_bytes_written    : u64,
117  /// event id check - missing event ids
118  pub n_evid_missing     : u64,
119  /// event id check - chunksize
120  pub n_evid_chunksize   : u64,
121  /// length of incoming buffer for 
122  /// the thread
123  /// check for missing event ids
124  pub evid_missing       : u64,
125  /// probe size for missing event id check
126  pub evid_check_len     : u64,
127  /// number of packets written to disk
128  pub n_pack_write_disk  : u64,
129  /// length of the incoming channel, which 
130  /// is basically packets queued to be sent
131  pub incoming_ch_len    : u64,
132}
133
134impl HeartBeatDataSink {
135
136  pub fn new() -> Self {
137    Self {
138      met                : 0,
139      n_packets_sent     : 0,
140      n_packets_incoming : 0,
141      n_bytes_written    : 0,
142      n_evid_missing     : 0,
143      n_evid_chunksize   : 0,
144      evid_missing       : 0,
145      evid_check_len     : 0,
146      n_pack_write_disk  : 0,
147      incoming_ch_len    : 0,
148    }
149  }
150
151  pub fn get_sent_packet_rate(&self) -> f64 {
152    self.n_packets_sent as f64 /  self.met as f64
153  }
154
155  pub fn get_mbytes_to_disk_per_sec(&self) -> f64 {
156    self.n_bytes_written as f64/(1e6 * self.met as f64)
157  }
158
159  pub fn to_string(&self) -> String {
160    let mut repr = String::from("<HearBeatDataSink");
161    repr += &(format!("\n \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} DATA SENDER HEARTBEAT \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B}"));
162    repr += &(format!("\n Sent {} TofPackets! (packet rate {:.2}/s)", self.n_packets_sent , self.get_sent_packet_rate()));
163    repr += &(format!("\n Writing events to disk: {} packets written, data write rate {:.2} MB/sec", self.n_pack_write_disk, self.get_mbytes_to_disk_per_sec()));
164    repr += &(format!("\n Missing evid analysis:  {} of {} a chunk of events missing ({:.2}%)", self.evid_missing, self.evid_check_len, 100.0*(self.evid_missing as f64/self.evid_check_len as f64)));
165    repr += &(format!("\n Incoming channel length: {}", self.incoming_ch_len));
166    repr += &(format!("\n \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} END HEARTBEAT \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B} \u{1F98B}"));
167    repr 
168  }
169}
170
171impl Default for HeartBeatDataSink {
172  fn default() -> Self {
173    Self::new()
174  }
175}
176
177impl Packable for HeartBeatDataSink {
178  const PACKET_TYPE : PacketType = PacketType::HeartBeatDataSink;
179}
180
181impl Serialization for HeartBeatDataSink {
182  
183  const HEAD : u16 = 0xAAAA;
184  const TAIL : u16 = 0x5555;
185  const SIZE : usize = 84; 
186  
187  fn from_bytestream(stream    : &Vec<u8>, 
188                     pos       : &mut usize) 
189    -> Result<Self, SerializationError>{
190    Self::verify_fixed(stream, pos)?;  
191    let mut hb = HeartBeatDataSink::new();
192    hb.met                = parse_u64(stream, pos);
193    hb.n_packets_sent     = parse_u64(stream, pos);
194    hb.n_packets_incoming = parse_u64(stream, pos);
195    hb.n_bytes_written    = parse_u64(stream, pos);
196    hb.n_evid_missing     = parse_u64(stream, pos);
197    hb.n_evid_chunksize   = parse_u64(stream, pos);
198    hb.evid_missing       = parse_u64(stream, pos);
199    hb.evid_check_len     = parse_u64(stream, pos);
200    hb.n_pack_write_disk  = parse_u64(stream, pos);
201    hb.incoming_ch_len    = parse_u64(stream, pos);
202    *pos += 2;
203    Ok(hb)
204  }
205  
206  fn to_bytestream(&self) -> Vec<u8> {
207    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
208    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
209    bs.extend_from_slice(&self.met.to_le_bytes());
210    bs.extend_from_slice(&self.n_packets_sent.to_le_bytes());
211    bs.extend_from_slice(&self.n_packets_incoming.to_le_bytes());
212    bs.extend_from_slice(&self.n_bytes_written.to_le_bytes());
213    bs.extend_from_slice(&self.n_evid_missing.to_le_bytes());
214    bs.extend_from_slice(&self.n_evid_chunksize.to_le_bytes());
215    bs.extend_from_slice(&self.evid_missing     .to_le_bytes() );
216    bs.extend_from_slice(&self.evid_check_len   .to_le_bytes() );
217    bs.extend_from_slice(&self.n_pack_write_disk.to_le_bytes() );
218    bs.extend_from_slice(&self.incoming_ch_len.to_le_bytes());
219    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
220    bs
221  }
222}
223
224#[cfg(feature = "random")]
225impl FromRandom for HeartBeatDataSink {
226  fn from_random() -> Self {
227    let mut rng            = rand::thread_rng();
228    let met                = rng.gen::<u64>();
229    let n_packets_sent     = rng.gen::<u64>();
230    let n_packets_incoming = rng.gen::<u64>();
231    let n_bytes_written    = rng.gen::<u64>();
232    let n_evid_missing     = rng.gen::<u64>();
233    let n_evid_chunksize   = rng.gen::<u64>();
234    let evid_missing       = rng.gen::<u64>();
235    let evid_check_len     = rng.gen::<u64>();
236    let n_pack_write_disk  = rng.gen::<u64>();
237    let incoming_ch_len    = rng.gen::<u64>();
238    Self {
239      met,
240      n_packets_sent,
241      n_packets_incoming,
242      n_bytes_written,
243      n_evid_missing,
244      n_evid_chunksize,
245      evid_missing,
246      evid_check_len,
247      n_pack_write_disk,
248      incoming_ch_len
249    }
250  }
251}
252
253impl fmt::Display for HeartBeatDataSink {
254  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255    let repr = self.to_string();
256    write!(f, "{}", repr)
257  }
258}
259#[cfg(feature = "random")]
260#[test]
261fn pack_rbping() {
262  for _ in 0..100 {
263    let ping = RBPing::from_random();
264    let test : RBPing = ping.pack().unpack().unwrap();
265    assert_eq!(ping, test);
266  }
267}
268
269#[cfg(feature = "random")]
270#[test]
271fn pack_heartbeatdatasink() {
272  for _ in 0..100 {
273    let hb = HeartBeatDataSink::from_random();
274    let test : HeartBeatDataSink = hb.pack().unpack().unwrap();
275    assert_eq!(hb, test);
276  }
277}
278
279#[derive(Debug, Copy, Clone, PartialEq)]
280pub struct MTBHeartbeat {
281  pub version             : ProtocolVersion, 
282  pub total_elapsed       : u64, //aka met (mission elapsed time)
283  pub n_events            : u64,
284  pub evq_num_events_last : u64,
285  pub evq_num_events_avg  : u64,
286  pub n_ev_unsent         : u64,
287  pub n_ev_missed         : u64,
288  pub trate               : u64,
289  pub lost_trate          : u64,
290  // these will be available for ProtocolVersion::V1
291  pub prescale_track      : f32,
292  pub prescale_gaps       : f32,
293
294}
295
296impl MTBHeartbeat {
297  pub fn new() -> Self {
298    Self {
299      version             : ProtocolVersion::Unknown,
300      total_elapsed       : 0,
301      n_events            : 0,
302      evq_num_events_last : 0,
303      evq_num_events_avg  : 0,
304      n_ev_unsent         : 0,
305      n_ev_missed         : 0,
306      trate               : 0,
307      lost_trate          : 0,
308      // available for protocol version V1 and larger
309      prescale_track      : 0.0,
310      prescale_gaps       : 0.0,
311    }
312  }
313
314  pub fn get_sent_packet_rate(&self) -> f64 {
315    self.n_events as f64 / self.total_elapsed as f64
316  }
317
318  // get the prescale for the secondary trigger
319  pub fn get_prescale_track(&self) -> f64 {
320    if self.version == ProtocolVersion::Unknown {
321      error!("Prescale not available for protocol version < V1!");
322      return 0.0;
323    }
324    return self.prescale_track as f64
325  }
326  
327  // get the prescale for the secondary trigger
328  pub fn get_prescale_gaps(&self) -> f64 {
329    if self.version == ProtocolVersion::Unknown {
330      error!("Prescale not available for protocol version < V1!");
331      return 0.0;
332    }
333    return self.prescale_gaps as f64
334  }
335
336
337  pub fn to_string(&self) -> String {
338    let mut repr = format!("<MTBHeartbeats (version : {})", self.version);
339    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} "));
340    repr += &(format!("\n MET (Mission Elapsed Time)  : {:.1} sec", self.total_elapsed));
341    repr += &(format!("\n Num. recorded Events        : {}", self.n_events));
342    repr += &(format!("\n Last MTB EVQ size           : {}", self.evq_num_events_last));
343    repr += &(format!("\n Avg. MTB EVQ size (per 30s ): {:.2}", self.evq_num_events_avg));
344    repr += &(format!("\n trigger rate, recorded:     : {:.2} Hz", self.n_events as f64 / self.total_elapsed as f64));
345    repr += &(format!("\n trigger rate, from register : {:.2} Hz", self.trate));
346    repr += &(format!("\n lost trg rate, from register: {:.2} Hz", self.lost_trate));
347    if self.n_ev_unsent > 0 {
348        repr += &(format!("\n Num. sent errors        : {}", self.n_ev_unsent).bold());
349    }
350    if self.n_ev_missed > 0 {
351        repr += &(format!("\n Num. missed events      : {}", self.n_ev_missed).bold());
352    }
353    if self.version != ProtocolVersion::Unknown {
354        repr += &(format!("\n Prescale, prim. ('GAPS') trg : {:.4}", self.prescale_gaps));
355        repr += &(format!("\n Prescale  sec. ('Track') trg : {:.4}", self.prescale_track));
356    }
357    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} "));
358    repr
359  }
360}
361  
362
363impl Default for MTBHeartbeat {
364  fn default () -> Self {
365    Self::new()
366  }
367}
368
369impl Packable for MTBHeartbeat {
370  const PACKET_TYPE : PacketType = PacketType::MTBHeartbeat;
371}
372
373impl Serialization for MTBHeartbeat {
374  const HEAD : u16 = 0xAAAA;
375  const TAIL : u16 = 0x5555;
376  const SIZE : usize = 68;
377
378  fn from_bytestream(stream    :&Vec<u8>,
379                     pos       :&mut usize)
380  -> Result<Self, SerializationError>{
381    Self::verify_fixed(stream, pos)?;
382    let mut hb = MTBHeartbeat::new();
383    hb.total_elapsed          = parse_u64(stream, pos);
384    hb.n_events               = parse_u64(stream, pos);
385    hb.evq_num_events_last    = parse_u64(stream, pos);
386    hb.evq_num_events_avg     = parse_u64(stream, pos);
387    hb.n_ev_unsent            = parse_u64(stream, pos);
388    hb.n_ev_missed            = parse_u64(stream, pos);
389    // we use only 48bit here to carve out space for the 
390    // protocol version and the prescales
391    // this is a hack, but since we are expeting rates
392    // < 65kHz, we should be fine with only 16bit for the 
393    // rate and can use the rest for the prescale
394    //let version_ps_rate       = parse_u64(stream, pos);
395    //let version               = version_ps_rate & 0xff00000000000000;
396    //let prescale_track        = version_ps_rate & 0x00ffffffff000000;
397    //let trate                 = version_ps_rate & 0x0000000000ffffff;
398    //hb.version                = ProtocolVersion::from((version >> 56) as u8); 
399    hb.version                = ProtocolVersion::from(parse_u8(stream, pos) as u8);
400    *pos += 1;
401    hb.trate                  = parse_u16(stream, pos) as u64;
402    hb.prescale_track         = parse_f32(stream, pos);
403    *pos += 2;
404    hb.lost_trate             = parse_u16(stream, pos) as u64;
405    hb.prescale_gaps          = parse_f32(stream, pos);
406    if hb.version == ProtocolVersion::Unknown {
407      hb.prescale_gaps  = 0.0;
408      hb.prescale_track = 0.0
409    }
410    *pos += 2;
411    Ok(hb)
412  }
413
414  fn to_bytestream(&self) -> Vec<u8> {
415    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
416    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
417    bs.extend_from_slice(&self.total_elapsed.to_le_bytes());
418    bs.extend_from_slice(&self.n_events.to_le_bytes());
419    bs.extend_from_slice(&self.evq_num_events_last.to_le_bytes());
420    bs.extend_from_slice(&self.evq_num_events_avg.to_le_bytes());
421    bs.extend_from_slice(&self.n_ev_unsent.to_le_bytes());
422    bs.extend_from_slice(&self.n_ev_missed.to_le_bytes());
423    bs.push(self.version as u8);
424    bs.push(0u8);
425    let short_trate = (self.trate & 0x0000000000ffffff) as u16;
426    bs.extend_from_slice(&short_trate.to_le_bytes());
427    bs.extend_from_slice(&self.prescale_track.to_le_bytes());
428    let short_lrate = (self.lost_trate & 0x0000000000ffffff) as u16;
429    // FIXME - not needed, just filler
430    bs.extend_from_slice(&short_lrate.to_le_bytes());
431    bs.extend_from_slice(&short_lrate.to_le_bytes());
432    bs.extend_from_slice(&self.prescale_gaps.to_le_bytes());
433    //let rate_n_prescale_track =
434    //    (((self.version as u8) as u64) << 56)
435    //  | (self.prescale_track as u64) << 24 
436    //  | (self.trate & 0x0000000000ffffff);
437    //bs.extend_from_slice(&rate_n_prescale_track.to_le_bytes());
438    //let rate_n_prescale_gaps = 
439    // ((self.prescale_gaps as f64)   << 24)
440    // | (self.lost_trate & 0x0000000000ffffff);
441    //bs.extend_from_slice(&rate_n_prescale_gaps.to_le_bytes());
442    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
443    bs
444  }
445}
446
447#[cfg(feature = "random")]
448impl FromRandom for MTBHeartbeat {
449  fn from_random() -> Self {
450    let mut hb = Self::new();
451    let mut rng             = rand::thread_rng();
452    hb.total_elapsed       = rng.gen::<u64>();
453    hb.n_events            = rng.gen::<u64>();
454    hb.evq_num_events_last = rng.gen::<u64>();
455    hb.evq_num_events_avg  = rng.gen::<u64>();
456    hb.n_ev_unsent         = rng.gen::<u64>();
457    hb.n_ev_missed         = rng.gen::<u64>();
458    hb.trate               = rng.gen::<u16>() as u64;
459    hb.lost_trate          = rng.gen::<u16>() as u64;
460    hb.version             = ProtocolVersion::from_random();
461    if hb.version != ProtocolVersion::Unknown {
462      hb.prescale_gaps       = rng.gen::<f32>();
463      hb.prescale_track      = rng.gen::<f32>();
464    }
465    hb
466  }
467}
468
469impl fmt::Display for MTBHeartbeat {
470  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471    let repr = self.to_string();
472    write!(f, "{}", repr)
473  }
474} 
475
476#[cfg(feature="random")]
477#[test]
478fn pack_mtbheartbeat() {
479  for _ in 0..100 {
480    let hb = MTBHeartbeat::from_random();
481    let test : MTBHeartbeat = hb.pack().unpack().unwrap();
482    assert_eq!(hb, test);
483  }
484} 
485
486#[derive(Debug, Copy, Clone, PartialEq)]
487pub struct EVTBLDRHeartbeat {
488  /// Mission elapsed time in seconds
489  pub met_seconds           : usize,
490  /// Total number of received MasterTriggerEvents (from MTB)
491  pub n_mte_received_tot    : usize,
492  /// Total number of received RBEvents (from all RB)
493  pub n_rbe_received_tot    : usize,
494  /// Average number of RBEvents per each MTEvent
495  pub n_rbe_per_te          : usize,
496  /// Total number of discarded RBEvents (accross all boards)
497  pub n_rbe_discarded_tot   : usize,
498  /// TOtal number of missed MTEvents. "Skipped means" gaps in 
499  /// consecutive rising event ids
500  pub n_mte_skipped         : usize,
501  /// Total number of events that timed out, which means they 
502  /// got send before all RBEvents could be associated with 
503  /// this event
504  pub n_timed_out           : usize,
505  /// Total number of events passed on to the gloabl data sink 
506  /// thread
507  pub n_sent                : usize,
508  /// ?
509  pub delta_mte_rbe         : usize,
510  /// The total size of the current event cache in number of events
511  pub event_cache_size      : usize,
512  /// In paralel to the event_cache, the event_id cache holds event ids.
513  /// This should be perfectly aligned to the event_cache by design.
514  pub event_id_cache_size   : usize, 
515  /// The total number of hits which we lost due to the DRS being busy
516  /// (this is on the Readoutboards)
517  pub drs_bsy_lost_hg_hits  : usize,
518  /// The total number of RBEvents which do not have a MasterTriggerEvent
519  pub rbe_wo_mte            : usize,
520  /// The current length of the channel which we use to send events from 
521  /// the MasterTrigger thread to the event builder
522  pub mte_receiver_cbc_len  : usize,
523  /// The current length of the channel whcih we use for all readoutboard
524  /// threads to send their events to the event builder
525  pub rbe_receiver_cbc_len  : usize,
526  /// the current length of the channel which we use to send built events 
527  /// to the global data sink thread
528  pub tp_sender_cbc_len     : usize,
529  /// The total number of RBEvents which have an event id which is SMALLER
530  /// than the smallest event id in the event cache. 
531  pub n_rbe_from_past       : usize,
532  pub n_rbe_orphan          : usize,
533  // let's deprecate this!
534  pub n_rbe_per_loop          : usize,
535  /// The totabl number of events with the "AnyDataMangling" flag set
536  pub data_mangled_ev       : usize,
537  // pub seen_rbevents         : HashMap<u8, usize>,
538}
539
540impl EVTBLDRHeartbeat {
541  // pub fn new() -> Self {
542  //   let mut seen_rbevents = HashMap::<u8, usize>::new();
543  //   for k in 1..47 {
544  //     if k == 10 || k ==12 || k == 37 || k == 38 || k == 43 || k == 45 {
545  //       continue;
546  //     } else {
547  //       seen_rbevents.insert(k as u8, 0);
548  //     }
549  //   }
550  pub fn new() -> Self {
551    Self {
552      met_seconds          : 0,
553      n_mte_received_tot   : 0,
554      n_rbe_received_tot   : 0,
555      n_rbe_per_te         : 0,
556      n_rbe_discarded_tot  : 0,
557      n_mte_skipped        : 0,
558      n_timed_out          : 0,
559      n_sent               : 0,
560      delta_mte_rbe        : 0,
561      event_cache_size     : 0,
562      event_id_cache_size  : 0,
563      drs_bsy_lost_hg_hits : 0,
564      rbe_wo_mte           : 0,
565      mte_receiver_cbc_len : 0,
566      rbe_receiver_cbc_len : 0,
567      tp_sender_cbc_len    : 0,
568      n_rbe_per_loop         : 0,
569      n_rbe_orphan         : 0,
570      n_rbe_from_past      : 0,
571      data_mangled_ev      : 0,
572      // seen_rbevents        : seen_rbevents, 
573    }
574  }
575
576  pub fn get_average_rbe_te(&self) -> f64 {
577   if self.n_sent > 0 {
578     return self.n_rbe_per_te as f64 / self.n_sent as f64;
579   }
580   0.0
581  }
582
583  pub fn get_timed_out_frac(&self) -> f64 {
584    if self.n_sent > 0 {
585      return self.n_timed_out as f64 / self.n_sent as f64;
586    }
587    0.0
588  }
589
590  // pub fn add_rbevent(&mut self, rb_id : u8) {
591  //   *self.seen_rbevents.get_mut(&rb_id).unwrap() += 1;
592  // }
593  
594  pub fn get_incoming_vs_outgoing_mte(&self) -> f64 {
595    if self.n_sent > 0 {
596      return self.n_mte_received_tot as f64 /  self.n_sent as f64;
597    }
598    0.0
599  }
600
601  pub fn get_nrbe_discarded_frac(&self) -> f64 {
602    if self.n_rbe_received_tot > 0 {
603     return self.n_rbe_discarded_tot as f64 / self.n_rbe_received_tot as f64;
604   }
605   0.0
606  }
607  
608  pub fn get_mangled_frac(&self) -> f64 {
609    if self.n_mte_received_tot > 0 {
610     return self.data_mangled_ev as f64 / self.n_mte_received_tot as f64;
611   }
612   0.0
613  }
614
615  pub fn get_drs_lost_frac(&self) -> f64 {
616    if self.n_rbe_received_tot > 0 {
617      return self.drs_bsy_lost_hg_hits as f64 / self.n_rbe_received_tot as f64;
618    }
619    0.0
620  }
621
622  pub fn to_string(&self) -> String {
623    let mut repr = String::from("");
624    repr += &(format!("\n \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50} EVENTBUILDER HEARTBTEAT \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50} "));
625    repr += &(format!("\n Mission elapsed time (MET) [s]      : {}", self.met_seconds).bright_purple());
626    repr += &(format!("\n Num. events sent                    : {}", self.n_sent).bright_purple());
627    repr += &(format!("\n Size of event cache                 : {}", self.event_cache_size).bright_purple());
628    //repr += &(format!("\n Size of event ID cache              : {}", self.event_id_cache_size).bright_purple());
629    repr += &(format!("\n Num. events timed out               : {}", self.n_timed_out).bright_purple());
630    repr += &(format!("\n Percent events timed out            : {:.2}%", self.get_timed_out_frac()*(100 as f64)).bright_purple());
631    //if self.n_sent > 0 && self.n_rbe_per_loop > 0 {
632    //  repr += &(format!("\n Percent events w/out event ID : {:.2}%", (((self.n_rbe_per_loop / self.n_sent) as f64)*(100 as f64))).bright_purple());
633    //} else if self.n_rbe_per_loop > 0 { 
634    //  repr += &(format!("\n Percent events w/out event ID : N/A").bright_purple());
635    //}
636    if self.n_mte_received_tot > 0{ 
637      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}"));
638      repr += &(format!("\n Num. evts with ANY data mangling  : {}"     , self.data_mangled_ev));
639      repr += &(format!("\n Per. evts with ANY data mangling  : {:.2}%" , self.get_mangled_frac()*(100 as f64)));
640    }
641    else {repr += &(format!("\n Percent events with data mangling: unable to calculate"));}
642    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}"));
643    repr += &(format!("\n Received MTEvents                   : {}", self.n_mte_received_tot).bright_purple());
644    repr += &(format!("\n Skipped MTEvents                    : {}", self.n_mte_skipped).bright_purple());
645    repr += &(format!("\n Incoming/outgoing MTEvents fraction : {:.2}", self.get_incoming_vs_outgoing_mte()).bright_purple());
646    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}"));
647    repr += &(format!("\n Received RBEvents                   : {}", self.n_rbe_received_tot).bright_purple());
648    repr += &(format!("\n RBEvents Discarded                  : {}", self.n_rbe_discarded_tot).bright_purple());
649    repr += &(format!("\n Percent RBEvents discarded          : {:.2}%", self.get_nrbe_discarded_frac()*(100 as f64)).bright_purple());
650    repr += &(format!("\n DRS4 busy lost hits                 : {}", self.drs_bsy_lost_hg_hits).bright_purple());
651    repr += &(format!("\n RDS4 busy lost hits fraction        : {:.2}%", self.get_drs_lost_frac()*(100.0 as f64)).bright_purple());
652    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}"));
653    if self.n_sent > 0 && self.n_mte_received_tot > 0 {
654        repr += &(format!("\n RBEvent/Evts sent               : {:.2}", (self.n_rbe_received_tot as f64/ self.n_sent as f64)).bright_purple());
655        repr += &(format!("\n RBEvent/MTEvents                : {:.2}", (self.n_rbe_received_tot as f64 / self.n_mte_received_tot as f64)).bright_purple()); }
656    repr += &(format!("\n Current RBevents / iteration        : {:.2}", self.n_rbe_per_loop).bright_purple());
657    repr += &(format!("\n Num. RBEvents with evid from past   : {}",  self.n_rbe_from_past).bright_purple());
658    repr += &(format!("\n Num. orphan RBEvents                : {}",  self.n_rbe_orphan).bright_purple());
659    repr += &(format!("\n\n Getting MTE from cache for RBEvent failed {} times :(", self.rbe_wo_mte).bright_blue());
660    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}"));
661    repr += &(format!("\n Ch. len MTE Receiver                : {}", self.mte_receiver_cbc_len).bright_purple());
662    repr += &(format!("\n Ch. len RBE Reveiver                : {}", self.rbe_receiver_cbc_len).bright_purple());
663    repr += &(format!("\n Ch. len TP Sender                   : {}", self.tp_sender_cbc_len).bright_purple());
664    repr += &(format!("\n \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50} END EVENTBUILDER HEARTBTEAT \u{2B50} \u{2B50} \u{2B50} \u{2B50} \u{2B50}"));
665    repr
666  }
667}
668
669impl Default for EVTBLDRHeartbeat {
670  fn default () -> Self {
671    Self::new()
672  }
673}
674
675impl Packable for EVTBLDRHeartbeat {
676  const PACKET_TYPE : PacketType = PacketType::EVTBLDRHeartbeat;
677}
678
679impl Serialization for EVTBLDRHeartbeat {
680  const HEAD : u16 = 0xAAAA;
681  const TAIL : u16 = 0x5555;
682  const SIZE : usize = 156; //
683
684  fn from_bytestream(stream : &Vec<u8>, 
685                     pos        : &mut usize)
686    -> Result<Self, SerializationError>{
687    Self::verify_fixed(stream,pos)?;
688    let mut hb = EVTBLDRHeartbeat::new();
689    hb.met_seconds          = parse_usize(stream,pos);
690    hb.n_mte_received_tot   = parse_usize(stream,pos);
691    hb.n_rbe_received_tot   = parse_usize(stream,pos);
692    hb.n_rbe_per_te         = parse_usize(stream,pos);
693    hb.n_rbe_discarded_tot  = parse_usize(stream,pos);
694    hb.n_mte_skipped        = parse_usize(stream,pos);
695    hb.n_timed_out          = parse_usize(stream,pos);
696    hb.n_sent               = parse_usize(stream,pos);
697    hb.delta_mte_rbe        = parse_usize(stream,pos);
698    hb.event_cache_size     = parse_usize(stream,pos);
699    //hb.event_id_cache_size  = parse_usize(stream,pos);
700    hb.drs_bsy_lost_hg_hits = parse_usize(stream,pos);
701    hb.rbe_wo_mte           = parse_usize(stream,pos);
702    hb.mte_receiver_cbc_len = parse_usize(stream,pos);
703    hb.rbe_receiver_cbc_len = parse_usize(stream,pos);
704    hb.tp_sender_cbc_len    = parse_usize(stream,pos);
705    hb.n_rbe_per_loop         = parse_usize(stream,pos);
706    hb.n_rbe_from_past      = parse_usize(stream,pos);
707    hb.n_rbe_orphan         = parse_usize(stream,pos);
708    hb.data_mangled_ev      = parse_usize(stream,pos);
709    // hb.seen_rbevents        = HashMap::from(parse_u8(stream, pos));
710    *pos += 2;
711    Ok(hb)
712  }
713    
714  fn to_bytestream(&self) -> Vec<u8> {
715    let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
716    bs.extend_from_slice(&Self::HEAD.to_le_bytes());
717    bs.extend_from_slice(&self.met_seconds.to_le_bytes());
718    bs.extend_from_slice(&self.n_mte_received_tot.to_le_bytes());
719    bs.extend_from_slice(&self.n_rbe_received_tot.to_le_bytes());
720    bs.extend_from_slice(&self.n_rbe_per_te.to_le_bytes());
721    bs.extend_from_slice(&self.n_rbe_discarded_tot.to_le_bytes());
722    bs.extend_from_slice(&self.n_mte_skipped.to_le_bytes());
723    bs.extend_from_slice(&self.n_timed_out.to_le_bytes());
724    bs.extend_from_slice(&self.n_sent.to_le_bytes());
725    bs.extend_from_slice(&self.delta_mte_rbe.to_le_bytes());
726    bs.extend_from_slice(&self.event_cache_size.to_le_bytes());
727    //bs.extend_from_slice(&self.event_id_cache_size.to_le_bytes());
728    bs.extend_from_slice(&self.drs_bsy_lost_hg_hits.to_le_bytes());
729    bs.extend_from_slice(&self.rbe_wo_mte.to_le_bytes());
730    bs.extend_from_slice(&self.mte_receiver_cbc_len.to_le_bytes());
731    bs.extend_from_slice(&self.rbe_receiver_cbc_len.to_le_bytes());
732    bs.extend_from_slice(&self.tp_sender_cbc_len.to_le_bytes());
733    bs.extend_from_slice(&self.n_rbe_per_loop.to_le_bytes());
734    bs.extend_from_slice(&self.n_rbe_from_past.to_le_bytes());
735    bs.extend_from_slice(&self.n_rbe_orphan.to_le_bytes());
736    bs.extend_from_slice(&self.data_mangled_ev.to_le_bytes());
737    // bs.push(self.seen_rbevents.to_u8());
738    bs.extend_from_slice(&Self::TAIL.to_le_bytes());
739    bs
740  }
741}
742
743#[cfg(feature="random")]
744impl FromRandom for EVTBLDRHeartbeat {
745  fn from_random() -> Self {
746    let mut rng       = rand::thread_rng();
747    let met_seconds   = rng.gen::<usize>();
748    let n_mte_received_tot = rng.gen::<usize>();
749    let n_rbe_received_tot = rng.gen::<usize>();
750    let n_rbe_per_te = rng.gen::<usize>();
751    let n_rbe_discarded_tot = rng.gen::<usize>();
752    let n_mte_skipped = rng.gen::<usize>();
753    let n_timed_out = rng.gen::<usize>();
754    let n_sent = rng.gen::<usize>();
755    let delta_mte_rbe = rng.gen::<usize>();
756    let event_cache_size = rng.gen::<usize>();
757    //let event_id_cache_size = rng.gen::<usize>();
758    let drs_bsy_lost_hg_hits  = rng.gen::<usize>();
759    let rbe_wo_mte = rng.gen::<usize>();
760    let mte_receiver_cbc_len = rng.gen::<usize>();
761    let rbe_receiver_cbc_len = rng.gen::<usize>();
762    let tp_sender_cbc_len = rng.gen::<usize>();
763    let n_rbe_per_loop = rng.gen::<usize>();
764    let n_rbe_from_past = rng.gen::<usize>();
765    let n_rbe_orphan = rng.gen::<usize>();
766    let data_mangled_ev = rng.gen::<usize>();
767    Self {
768      met_seconds,
769      n_rbe_received_tot,
770      n_rbe_per_te,
771      n_rbe_discarded_tot,
772      n_mte_skipped,
773      n_timed_out,
774      n_sent,
775      delta_mte_rbe,
776      event_cache_size,
777      // don't randomize this, since it 
778      // won't get serialized
779      event_id_cache_size : 0,
780      drs_bsy_lost_hg_hits,
781      rbe_wo_mte,
782      mte_receiver_cbc_len,
783      rbe_receiver_cbc_len,
784      tp_sender_cbc_len,
785      n_mte_received_tot,
786      n_rbe_per_loop,
787      n_rbe_from_past,
788      n_rbe_orphan,
789      data_mangled_ev
790    }
791  }
792} 
793
794impl fmt::Display for EVTBLDRHeartbeat {
795  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
796    let mut repr = String::from("<EVTBLDRHearbeat:   ");
797    repr += &self.to_string();
798    write!(f, "{}>", repr)
799  }
800}  
801
802#[cfg(feature="random")]
803#[test]
804fn pack_evtbldrheartbeat() {
805  for _ in 0..100 {
806    let hb = EVTBLDRHeartbeat::from_random();
807    let test : EVTBLDRHeartbeat = hb.pack().unpack().unwrap();
808    assert_eq!(hb, test);
809  }
810}