tof_dataclasses/events/
tof_event.rs

1//! Event strucutures for data reconrded by the tof
2//!
3
4use std::time::Instant;
5use std::fmt;
6use std::f32::consts::PI;
7
8cfg_if::cfg_if! {
9  if #[cfg(feature = "random")]  {
10    use crate::FromRandom;
11    use rand::Rng;
12  }
13}
14
15use crate::serialization::{
16  Serialization,
17  Packable,
18  parse_u8,
19  parse_u16,
20  parse_u32,
21  parse_u64,
22  parse_f32,
23  search_for_u16
24};
25
26use crate::packets::{
27  TofPacket,
28  PacketType
29};
30
31use crate::errors::SerializationError;
32
33use crate::events::{
34  MasterTriggerEvent,
35  RBEvent,
36  TofHit,
37  RBWaveform,
38  //RBMissingHit,
39  TriggerType,
40  EventStatus,
41  transcode_trigger_sources,
42};
43
44use crate::events::master_trigger::{
45  LTBThreshold,
46  LTB_CHANNELS
47};
48
49use crate::ProtocolVersion;
50
51cfg_if::cfg_if! {
52  if #[cfg(feature = "database")]  {
53    use crate::database::DsiJChPidMapping;
54    use crate::database::Paddle;
55    use std::collections::HashMap;
56  }
57}
58
59// #[cfg(feature ="database")]
60// use crate::database::Paddle;
61
62// This looks like a TODO
63#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
64#[repr(u8)]
65pub enum CompressionLevel {
66  Unknown = 0u8,
67  None    = 10u8,
68}
69
70impl fmt::Display for CompressionLevel {
71  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72    let r = serde_json::to_string(self).unwrap_or(
73      String::from("Error: cannot unwrap this CompressionLevel"));
74    write!(f, "<CompressionLevel: {}>", r)
75  }
76}
77
78impl From<u8> for CompressionLevel {
79  fn from(value: u8) -> Self {
80    match value {
81      0u8  => CompressionLevel::Unknown,
82      10u8 => CompressionLevel::None,
83      _    => CompressionLevel::Unknown
84    }
85  }
86}
87
88#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
89#[repr(u8)]
90pub enum EventQuality {
91  Unknown        =  0u8,
92  Silver         = 10u8,
93  Gold           = 20u8,
94  Diamond        = 30u8,
95  FourLeafClover = 40u8,
96}
97
98impl fmt::Display for EventQuality {
99  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100    let r = serde_json::to_string(self).unwrap_or(
101      String::from("Error: cannot unwrap this EventQuality"));
102    write!(f, "<EventQuality: {}>", r)
103  }
104}
105
106impl From<u8> for EventQuality {
107  fn from(value: u8) -> Self {
108    match value {
109      0u8  => EventQuality::Unknown,
110      10u8 => EventQuality::Silver,
111      20u8 => EventQuality::Gold,
112      30u8 => EventQuality::Diamond,
113      40u8 => EventQuality::FourLeafClover,
114      _    => EventQuality::Unknown
115    }
116  }
117}
118
119// FIXME - no PartialEq (or we have to implent it
120// since the times will never be equal
121#[derive(Debug, Clone)]
122pub struct TofEvent {
123
124  pub compression_level : CompressionLevel,
125  pub quality           : EventQuality,
126  pub header            : TofEventHeader,
127  pub mt_event          : MasterTriggerEvent,
128  pub rb_events         : Vec::<RBEvent>,
129  //pub missing_hits      : Vec::<RBMissingHit>, 
130  
131  // won't get serialized
132  pub creation_time     : Instant,
133  pub write_to_disk     : bool, 
134  pub paddles_set       : bool
135}
136
137impl fmt::Display for TofEvent {
138  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139    write!(f, 
140"<TofEvent:
141     quality        :  {}
142     {} 
143     {}
144     n RBEvents      : {}>"
145            ,self.quality,
146            self.header,
147            self.mt_event,
148            self.rb_events.len())
149  }
150}
151
152impl Default for TofEvent {
153  fn default() -> Self {
154    Self::new()
155  }
156}
157
158impl TofEvent {
159
160  pub fn new() -> Self {
161    let creation_time = Instant::now();
162    Self {
163      compression_level : CompressionLevel::Unknown,
164      quality           : EventQuality::Unknown,
165      header            : TofEventHeader::new(),
166      mt_event          : MasterTriggerEvent::new(),
167      rb_events         : Vec::<RBEvent>::new(),
168      //missing_hits      : Vec::<RBMissingHit>::new(), 
169      creation_time     : creation_time,
170      write_to_disk     : true,
171      paddles_set       : false
172    }
173  }
174
175
176  #[cfg(feature="database")]
177  pub fn set_paddles(&mut self, paddles : &HashMap<u8, Paddle>) {
178    let mut nerror = 0u8;
179    for ev in &mut self.rb_events {
180      for h in &mut ev.hits {
181        match paddles.get(&h.paddle_id) {
182          None => {
183            error!("Got paddle id {} which is not in given map!", h.paddle_id);
184            nerror += 1;
185            continue;
186          }
187          Some(pdl) => {
188            h.set_paddle(pdl);
189          }
190        }
191      }
192    }
193    if nerror == 0 {
194      self.paddles_set = true;
195    }
196  }
197
198  /// Get the pointcloud of this event, sorted by time
199  /// 
200  /// # Returns
201  ///   (f32, f32, f32, f32, f32) : (x,y,z,t,edep)
202  pub fn get_pointcloud(&self) -> Option<Vec<(f32,f32,f32,f32,f32)>> {
203    let mut pc = Vec::<(f32,f32,f32,f32,f32)>::new();
204    if !self.paddles_set {
205      error!("Before getting the pointcloud, paddle information needs to be set for this event. Call TofEventSummary;:set_paddle");
206      return None;
207    }
208    for rbev in &self.rb_events {
209      for h in &rbev.hits {
210        let result = (h.x, h.y, h.z, h.get_t0(), h.get_edep());
211        pc.push(result);
212      }
213    }
214    Some(pc)
215  }
216
217  /// Compare the MasterTriggerEvent::trigger_hits with 
218  /// the actual hits to determine from which paddles
219  /// we should have received HG hits (from waveforms)
220  /// but we did not get them
221  ///
222  /// WARNING: The current implementation of this is 
223  /// rather slow and not fit for production use
224  /// FIXME - rewrite as a closure
225  #[cfg(feature="database")]
226  pub fn get_missing_paddles_hg(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
227    let mut missing = Vec::<u8>::new();
228    for th in self.mt_event.get_trigger_hits() {
229      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
230      let mut found = false;
231      for h in self.get_hits() {
232        if h.paddle_id == pid {
233          found = true;
234          break
235        }
236      }
237      if !found {
238        missing.push(pid);
239      }
240    }
241    missing
242  }
243  
244  /// Compare the MasterTriggerEvent::trigger_hits with 
245  /// the actual hits to determine from which paddles
246  /// we have received more hits than we were supposed to.
247  /// These hits are neither in the trigger hits nor
248  /// rb_link_ids
249  ///
250  /// FIXME - this can be hits which are exclusively 
251  ///         within the RB integration window
252  #[cfg(feature="database")]
253  pub fn get_extra_paddles_hg(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
254    let mut extra = Vec::<u8>::new();
255    let mut trigger_pids = Vec::<u8>::new(); 
256    for th in self.mt_event.get_trigger_hits() {
257      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
258      trigger_pids.push(pid);
259    }
260    for h in self.get_hits() {
261      if !trigger_pids.contains(&h.paddle_id) {
262        extra.push(h.paddle_id);
263      }
264    }
265    extra
266  }
267  
268  /// Compare the MasterTriggerEvent::trigger_hits with 
269  /// the actual recorded waveforms to determine from which paddles
270  /// we should have received waveforms from. This is 
271  /// independent of the hits, which additionally required
272  /// that the hit extraction algorithm worked.
273  #[cfg(feature="database")]
274  pub fn get_missing_paddles_wf(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
275    let mut missing = Vec::<u8>::new();
276    let wf_pids = self.get_waveform_pids();
277    for th in self.mt_event.get_trigger_hits() {
278      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
279      // FIXME - rewrite this section so that it is more concise
280      let mut found = false;
281      for wf_pid in &wf_pids {
282        if *wf_pid == pid {
283          found = true;
284          break
285        }
286      }
287      if !found {
288        missing.push(pid);
289      }
290    }
291    missing
292  }
293
294  /// Get the triggered paddle ids
295  ///
296  /// Warning, this might be a bit slow
297  #[cfg(feature="database")]
298  pub fn get_triggered_paddles(&self, pid_map :   DsiJChPidMapping) -> Vec<u8> {
299    let mut paddles = Vec::<u8>::new();
300    for th in self.mt_event.get_trigger_hits() {
301      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
302      paddles.push(pid);
303    }
304    paddles
305  }
306  
307
308  pub fn extract_event_id_from_stream(stream : &Vec<u8>) 
309    -> Result<u32, SerializationError> {
310    // 2 + 2 + 2 + 2 + 4
311    let evid = parse_u32(stream, &mut 12);
312    Ok(evid)
313  }
314
315  pub fn age(&self) -> u64 {
316    self.creation_time.elapsed().as_secs()
317  }
318
319  /// Simple check if the event contains as much RBEvents 
320  /// as expected from the provided boards masks by the MTB
321  pub fn is_complete(&self) -> bool {
322    self.mt_event.get_rb_link_ids().len() == self.rb_events.len()
323  }
324 
325  /// A more advanced check, where events which are not in the 
326  /// provided mtb_link_id list don't count for completion
327  pub fn is_complete_masked(&self, mtb_link_ids_excluded : &Vec::<u8>) -> bool {
328    let mut expected_events = 0usize;
329    for k in &self.mt_event.get_rb_link_ids() {
330      if !mtb_link_ids_excluded.contains(k) {
331        expected_events += 1
332      }
333    }
334    self.rb_events.len() == expected_events
335  }
336
337  /// Encode the sizes of the vectors holding the 
338  /// into an u32
339  ///
340  /// We have one byte (256) max length per vector.
341  pub fn construct_sizes_header(&self) -> u32 {
342     let rb_event_len = self.rb_events.len() as u32;
343     // disable missing hits
344     //let miss_len     = self.missing_hits.len() as u32;
345     let miss_len     = 0u32;
346     let mut mask     = 0u32;
347     mask = mask | rb_event_len;
348     mask = mask | (miss_len << 8);
349     mask
350  }
351
352  pub fn decode_size_header(mask : &u32) 
353    -> (usize, usize) {
354    let rb_event_len = (mask & 0xFF)        as usize;
355    let miss_len     = ((mask & 0xFF00)     >> 8)  as usize;
356    (rb_event_len, miss_len)
357  }
358  
359  pub fn get_combined_vector_sizes(&self) -> usize {
360    self.rb_events.len() 
361    //+ self.missing_hits.len() 
362  }
363
364  /// Get all waveforms of all RBEvents in this event
365  pub fn get_rbwaveforms(&self) -> Vec<RBWaveform> {
366    let mut wf = Vec::<RBWaveform>::new();
367    for ev in &self.rb_events {
368      wf.extend_from_slice(&ev.get_rbwaveforms());
369    }
370    wf
371  }
372
373  /// Get all waveforms of all RBEvents in this event
374  /// ISSUE - Performance, Memory
375  /// FIXME - reimplement this things where this
376  ///         returns only a reference
377  pub fn get_waveforms(&self) -> Vec<RBWaveform> {
378    let mut wfs = Vec::<RBWaveform>::new();
379    for ev in &self.rb_events {
380      for wf in &ev.get_rbwaveforms() {
381        wfs.push(wf.clone());
382      }
383    }
384    wfs
385  }
386
387  /// Get all the paddles which have waveforms
388  pub fn get_waveform_pids(&self) -> Vec<u8> {
389    let mut pids = Vec::<u8>::new();
390    for ev in &self.rb_events {
391      for wf in &ev.get_rbwaveforms() {
392        pids.push(wf.paddle_id)
393      }
394    }
395    pids
396  }
397
398  /// Get all hits of all RBEvents in this event
399  pub fn get_hits(&self) -> Vec<TofHit> {
400    let mut hits = Vec::<TofHit>::new();
401    for ev in &self.rb_events {
402      for h in &ev.hits {
403        hits.push(*h);
404      }
405    }
406    hits
407  }
408
409  /// Check if th eassociated RBEvents have any of their
410  /// mangling stati set
411  pub fn has_any_mangling(&self) -> bool {
412    for rbev in &self.rb_events {
413      if rbev.status == EventStatus::CellAndChnSyncErrors 
414      || rbev.status == EventStatus::CellSyncErrors 
415      || rbev.status == EventStatus::ChnSyncErrors {
416        return true;
417      }
418    }
419    false
420  }
421
422  pub fn get_summary(&self) -> TofEventSummary {
423    let mut summary         = TofEventSummary::new();
424    // generate an aggregate status from all the different stati
425    summary.status          = self.mt_event.event_status;
426    if self.has_any_mangling() {
427      summary.status = EventStatus::AnyDataMangling;
428    }
429    // FIXME - this is not trigger paddles, but trigger hits!
430    summary.trigger_sources    = self.mt_event.trigger_source;
431    summary.n_trigger_paddles  = self.mt_event.get_trigger_hits().len() as u8;
432    summary.event_id           = self.header.event_id;
433    // truncate the run id to u16
434    summary.run_id             = (self.header.run_id & 0x0000ffff) as u16;
435    // FIXME we set the protocol version here, but that should propably 
436    // go elsewhere
437    summary.version            = ProtocolVersion::V1;
438    let mt_timestamp           = (self.mt_event.get_timestamp_abs48() as f64/1000.0).floor()  as u64; 
439    summary.timestamp32        = (mt_timestamp  & 0x00000000ffffffff ) as u32;
440    summary.timestamp16        = ((mt_timestamp & 0x0000ffff00000000 ) >> 32) as u16;
441    //summary.primary_beta       = self.header.primary_beta; 
442    //summary.primary_charge     = self.header.primary_charge; 
443    summary.dsi_j_mask         = self.mt_event.dsi_j_mask;
444    summary.channel_mask       = self.mt_event.channel_mask.clone();
445    summary.mtb_link_mask      = self.mt_event.mtb_link_mask;
446    summary.drs_dead_lost_hits = self.get_lost_hits();
447    summary.hits               = Vec::<TofHit>::new();
448    for ev in &self.rb_events {
449      for hit in &ev.hits {
450        let h = hit.clone();
451        if summary.version == ProtocolVersion::V1 {
452          if h.paddle_id <= 60 {
453            summary.n_hits_cbe += 1;
454            summary.tot_edep_cbe += h.get_edep();
455          }
456          else if h.paddle_id <= 108 && h.paddle_id > 60 {
457            summary.n_hits_umb += 1;
458            summary.tot_edep_umb += h.get_edep();
459          }
460          else {
461            summary.n_hits_cor += 1;
462            summary.tot_edep_cor += h.get_edep();
463          }
464        }
465        summary.hits.push(h);
466      }
467    }
468    #[cfg(feature="database")]
469    summary.normalize_hit_times();
470    summary
471  }
472  
473  /// The number of hits we did not get 
474  /// becaue of the DRS busy
475  pub fn get_lost_hits(&self) -> u16 {
476    let mut lost_hits = 0u16;
477    for rbev in &self.rb_events {
478      if rbev.header.drs_lost_trigger() {
479        let mut nhits = rbev.header.get_nchan() as u16;
480        if nhits > 0 {
481          nhits -= 1;
482        }
483        lost_hits += nhits;
484      }
485    }
486    lost_hits
487  }
488  
489  pub fn get_nhits_umb(&self) -> usize {
490    let mut nhit = 0;
491    for h in &self.get_hits() {
492      if h.paddle_id > 60 && h.paddle_id < 109 {
493        nhit += 1;
494      }
495    }
496    nhit
497  }
498
499  pub fn get_nhits(&self) -> usize {
500    self.get_hits().len()
501  }
502}
503
504impl Packable for TofEvent {
505  const PACKET_TYPE : PacketType = PacketType::TofEvent;
506}
507
508impl Serialization for TofEvent {
509  
510  const HEAD               : u16   = 43690; //0xAAAA
511  const TAIL               : u16   = 21845; //0x5555
512
513  // unify to_le_bytes and other in to_bytestream ? TODO
514  fn to_bytestream(&self) -> Vec<u8> {
515    let mut stream = Vec::<u8>::new();
516    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
517    stream.extend_from_slice(&(self.compression_level as u8).to_le_bytes());
518    stream.extend_from_slice(&(self.quality as u8).to_le_bytes());
519    stream.extend_from_slice(&self.header.to_bytestream());
520    stream.extend_from_slice(&self.mt_event.to_bytestream());
521    let sizes_header = self.construct_sizes_header();
522    stream.extend_from_slice(&sizes_header.to_le_bytes());
523    for k in 0..self.rb_events.len() {
524      stream.extend_from_slice(&self.rb_events[k].to_bytestream());
525    }
526    //for k in 0..self.missing_hits.len() {
527    //  stream.extend_from_slice(&self.missing_hits[k].to_bytestream());
528    //}
529    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
530    stream
531  }
532  
533  fn from_bytestream(stream    : &Vec<u8>, 
534                     pos       : &mut usize) 
535    -> Result<Self, SerializationError>{
536    let mut event = Self::new();
537    let head_pos = search_for_u16(Self::HEAD, stream, *pos)?; 
538    *pos = head_pos + 2;
539    event.compression_level = CompressionLevel::try_from(parse_u8(stream, pos)).unwrap();
540    event.quality           = EventQuality::try_from(parse_u8(stream, pos)).unwrap();
541    event.header            = TofEventHeader::from_bytestream(stream, pos)?;
542    event.mt_event          = MasterTriggerEvent::from_bytestream(stream, pos)?;
543    let v_sizes = Self::decode_size_header(&parse_u32(stream, pos));
544    for k in 0..v_sizes.0 {
545      match RBEvent::from_bytestream(stream, pos) {
546        Err(err) => error!("Expected RBEvent {} of {}, but got serialization error {}!", k,  v_sizes.0, err),
547        Ok(ev) => {
548          event.rb_events.push(ev);
549        }
550      }
551    }
552    let tail = parse_u16(stream, pos);
553    if tail != Self::TAIL {
554      error!("Decoding of TAIL failed! Got {} instead!", tail);
555    }
556    Ok(event)
557  }
558}
559
560#[cfg(feature="random")]
561impl FromRandom for TofEvent {
562
563  fn from_random() -> Self {
564    let mut event   = Self::new();
565    event.mt_event  = MasterTriggerEvent::from_random();
566    event.header    = TofEventHeader::from_random();
567    let mut rng     = rand::thread_rng();
568    let n_boards    = rng.gen_range(1..41) as u8;
569    //let n_boards    = rng.gen::<u8>() as usize;
570    //let n_paddles   = rng.gen::<u8>() as usize;
571    for _ in 0..n_boards {
572      event.rb_events.push(RBEvent::from_random());
573    }
574    //for _ in 0..n_missing {
575    //  event.missing_hits.push(RBMissingHit::from_random());
576    //}
577    // for now, we do not randomize CompressionLevel and qualtiy
578    //event.compression_level : CompressionLevel::,
579    //event.quality           : EventQuality::Unknown,
580    event
581  }
582}
583
584impl From<MasterTriggerEvent> for TofEvent {
585  fn from(mte : MasterTriggerEvent) -> Self {
586    let mut te : TofEvent = Default::default();
587    te.mt_event = mte;
588    te.header.event_id = te.mt_event.event_id;
589    te
590  }
591}
592
593/// The main event structure
594#[derive(Debug, Clone, PartialEq)]
595pub struct TofEventHeader  {
596
597  pub run_id       : u32,
598  pub event_id     : u32,
599  // lost hits insead of n_hit outer and n_hit inner tof
600  pub drs_dead_lost_hits  : u8,
601  pub rsvd0              : u8,
602  // the timestamp shall be comging from the master trigger
603  pub timestamp_32 : u32,
604  pub timestamp_16 : u16, // -> 14 byres
605  
606
607  // reconstructed quantities
608  pub primary_beta        : u16, 
609  pub primary_beta_unc    : u16, 
610  pub primary_charge      : u16, 
611  pub primary_charge_unc  : u16, 
612  pub primary_outer_tof_x : u16, 
613  pub primary_outer_tof_y : u16, 
614  pub primary_outer_tof_z : u16, 
615  pub primary_inner_tof_x : u16, 
616  pub primary_inner_tof_y : u16, 
617  pub primary_inner_tof_z : u16, //-> 20bytes primary 
618
619  //pub nhit_outer_tof       : u8,  
620  // no need to save this, can be 
621  // rereated from paddle_info.size() - nhit_outer_tof
622  //pub nhit_inner_tof       : u8, 
623
624  pub trigger_info         : u8,
625  pub ctr_etx              : u8,
626
627  // this field can be debated
628  // the reason we have it is 
629  // that for de/serialization, 
630  // we need to know the length 
631  // of the expected bytestream.
632  pub n_paddles           : u8, // we don't have more than 
633                               // 256 paddles.
634}
635
636impl TofEventHeader {
637  
638  pub fn new() -> Self {
639    Self {
640      run_id               : 0,
641      event_id             : 0,
642      drs_dead_lost_hits   : 0,
643      rsvd0               : 0,
644      timestamp_32         : 0,
645      timestamp_16         : 0,
646      primary_beta         : 0, 
647      primary_beta_unc     : 0, 
648      primary_charge       : 0, 
649      primary_charge_unc   : 0, 
650      primary_outer_tof_x  : 0, 
651      primary_outer_tof_y  : 0, 
652      primary_outer_tof_z  : 0, 
653      primary_inner_tof_x  : 0, 
654      primary_inner_tof_y  : 0, 
655      primary_inner_tof_z  : 0,  
656      //nhit_outer_tof       : 0,  
657      //nhit_inner_tof       : 0, 
658      trigger_info         : 0,
659      ctr_etx              : 0,
660      n_paddles            : 0  
661    }
662  }
663}
664
665impl Serialization for TofEventHeader {
666  const HEAD               : u16   = 0xAAAA;
667  const TAIL               : u16   = 0x5555;
668  const SIZE               : usize = 43; 
669
670  fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
671     -> Result<Self, SerializationError> {
672    Self::verify_fixed(stream, pos)?;
673    let mut event             = Self::new();
674    event.run_id              = parse_u32(stream, pos);
675    event.event_id            = parse_u32(stream, pos);
676    event.timestamp_32        = parse_u32(stream, pos);
677    event.timestamp_16        = parse_u16(stream, pos);
678    event.primary_beta        = parse_u16(stream, pos);
679    event.primary_beta_unc    = parse_u16(stream, pos);
680    event.primary_charge      = parse_u16(stream, pos);
681    event.primary_charge_unc  = parse_u16(stream, pos);
682    event.primary_outer_tof_x = parse_u16(stream, pos);
683    event.primary_outer_tof_y = parse_u16(stream, pos);
684    event.primary_outer_tof_z = parse_u16(stream, pos);
685    event.primary_inner_tof_x = parse_u16(stream, pos);
686    event.primary_inner_tof_y = parse_u16(stream, pos);
687    event.primary_inner_tof_z = parse_u16(stream, pos); 
688    event.drs_dead_lost_hits  = parse_u8(stream, pos);
689    event.rsvd0              = parse_u8(stream, pos);
690    //event.nhit_outer_tof      = parse_u8(stream, pos);
691    //event.nhit_inner_tof      = parse_u8(stream, pos);
692    event.trigger_info        = parse_u8(stream, pos);
693    event.ctr_etx             = parse_u8(stream, pos);
694    event.n_paddles           = parse_u8(stream, pos); 
695    *pos += 2; 
696    Ok(event) 
697  }
698  
699  fn to_bytestream(&self) -> Vec<u8> {
700    let mut bytestream = Vec::<u8>::with_capacity(Self::SIZE);
701    bytestream.extend_from_slice(&Self::HEAD                     .to_le_bytes());
702    bytestream.extend_from_slice(&self.run_id                    .to_le_bytes());
703    bytestream.extend_from_slice(&self.event_id                  .to_le_bytes());
704    bytestream.extend_from_slice(&self.timestamp_32              .to_le_bytes());
705    bytestream.extend_from_slice(&self.timestamp_16              .to_le_bytes());
706    bytestream.extend_from_slice(&self.primary_beta              .to_le_bytes());
707    bytestream.extend_from_slice(&self.primary_beta_unc          .to_le_bytes());
708    bytestream.extend_from_slice(&self.primary_charge            .to_le_bytes());
709    bytestream.extend_from_slice(&self.primary_charge_unc        .to_le_bytes());
710    bytestream.extend_from_slice(&self.primary_outer_tof_x       .to_le_bytes());
711    bytestream.extend_from_slice(&self.primary_outer_tof_y       .to_le_bytes());
712    bytestream.extend_from_slice(&self.primary_outer_tof_z       .to_le_bytes());
713    bytestream.extend_from_slice(&self.primary_inner_tof_x       .to_le_bytes());
714    bytestream.extend_from_slice(&self.primary_inner_tof_y       .to_le_bytes());
715    bytestream.extend_from_slice(&self.primary_inner_tof_z       .to_le_bytes());
716    //bytestream.extend_from_slice(&self.rb_events
717    //bytestream.extend_from_slice(&self.nhit_outer_tof            .to_le_bytes());
718    //bytestream.extend_from_slice(&self.nhit_inner_tof            .to_le_bytes());
719    bytestream.extend_from_slice(&self.drs_dead_lost_hits        .to_le_bytes());
720    bytestream.extend_from_slice(&self.rsvd0                    .to_le_bytes());
721    bytestream.extend_from_slice(&self.trigger_info              .to_le_bytes());
722    bytestream.extend_from_slice(&self.ctr_etx                   .to_le_bytes());
723    bytestream.extend_from_slice(&self.n_paddles                 .to_le_bytes());
724    bytestream.extend_from_slice(&Self::TAIL        .to_le_bytes()); 
725    bytestream
726  }
727}
728
729
730impl Default for TofEventHeader {
731  fn default() -> Self {
732    Self::new()
733  }
734}
735
736impl From<&MasterTriggerEvent> for TofEventHeader {
737  fn from(mte : &MasterTriggerEvent) -> Self {
738    let mut te               = Self::new();
739    te.event_id              = mte.event_id;
740    te.timestamp_32          = mte.timestamp;
741    te.n_paddles             = mte.get_trigger_hits().len() as u8;
742    te
743  }
744}
745
746impl fmt::Display for TofEventHeader {
747  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
748    let mut repr = String::from("<TofEventHeader"); 
749    repr += &(format!("\n  Run   ID          : {}", self.run_id              ));
750    repr += &(format!("\n  Event ID          : {}", self.event_id            ));
751    repr += &(format!("\n  Timestamp 32      : {}", self.timestamp_32        ));
752    repr += &(format!("\n  Timestamp 16      : {}", self.timestamp_16        ));
753    repr += &(format!("\n  DRS LOST HITS     : {}", self.drs_dead_lost_hits  ));
754    repr += &(format!("\n  Prim. Beta        : {}", self.primary_beta        ));
755    repr += &(format!("\n  Prim. Beta Unc    : {}", self.primary_beta_unc    ));
756    repr += &(format!("\n  Prim. Charge      : {}", self.primary_charge      ));
757    repr += &(format!("\n  Prim. Charge unc  : {}", self.primary_charge_unc  ));
758    repr += &(format!("\n  Prim. Outer Tof X : {}", self.primary_outer_tof_x ));
759    repr += &(format!("\n  Prim. Outer Tof Y : {}", self.primary_outer_tof_y ));
760    repr += &(format!("\n  Prim. Outer Tof Z : {}", self.primary_outer_tof_z ));
761    repr += &(format!("\n  Prim. Inner Tof X : {}", self.primary_inner_tof_x ));
762    repr += &(format!("\n  Prim. Inner Tof Y : {}", self.primary_inner_tof_y ));
763    repr += &(format!("\n  Prim. Inner Tof Z : {}", self.primary_inner_tof_z ));
764    //repr += &(format!("\n  NHit  Outer Tof   : {}", self.nhit_outer_tof      ));
765    //repr += &(format!("\n  NHit  Inner Tof   : {}", self.nhit_inner_tof      ));
766    repr += &(format!("\n  TriggerInfo       : {}", self.trigger_info        ));
767    repr += &(format!("\n  Ctr ETX           : {}", self.ctr_etx             ));
768    repr += &(format!("\n  NPaddles          : {}", self.n_paddles           ));
769    repr += ">";
770  write!(f,"{}", repr)
771  }
772}
773
774#[cfg(feature="random")]
775impl FromRandom for TofEventHeader {
776
777  fn from_random() -> Self {
778    let mut rng     = rand::thread_rng();
779    Self { 
780      run_id               : rng.gen::<u32>(),
781      event_id             : rng.gen::<u32>(),
782      drs_dead_lost_hits   : rng.gen::<u8>(),
783      rsvd0               : rng.gen::<u8>(),
784      timestamp_32         : rng.gen::<u32>(),
785      timestamp_16         : rng.gen::<u16>(),
786      primary_beta         : rng.gen::<u16>(), 
787      primary_beta_unc     : rng.gen::<u16>(), 
788      primary_charge       : rng.gen::<u16>(), 
789      primary_charge_unc   : rng.gen::<u16>(), 
790      primary_outer_tof_x  : rng.gen::<u16>(), 
791      primary_outer_tof_y  : rng.gen::<u16>(), 
792      primary_outer_tof_z  : rng.gen::<u16>(), 
793      primary_inner_tof_x  : rng.gen::<u16>(), 
794      primary_inner_tof_y  : rng.gen::<u16>(), 
795      primary_inner_tof_z  : rng.gen::<u16>(),  
796      trigger_info         : rng.gen::<u8>(),
797      ctr_etx              : rng.gen::<u8>(),
798      n_paddles            : rng.gen::<u8>()  
799    }
800  }
801}
802
803/// De-facto the main event class
804///
805/// TofEventSummary provides a list of extracted
806/// hits from the ReadoutBoards as well as 
807/// information about the trigger system.
808#[derive(Debug, Clone, PartialEq)]
809pub struct TofEventSummary {
810  pub status            : EventStatus,
811  pub version           : ProtocolVersion,
812  pub quality           : u8,
813  pub trigger_sources   : u16,
814
815  /// the number of triggered paddles coming
816  /// from the MTB directly. This might NOT be
817  /// the same as the number of hits!
818  pub n_trigger_paddles  : u8,
819  pub event_id           : u32,
820  /// NEW - uses the space for primary_beta,
821  /// which we won't have anyway
822  pub run_id             : u16,
823  pub timestamp32        : u32,
824  pub timestamp16        : u16,
825  /// DEPRECATED, won't get serialized
826  /// reconstructed primary beta
827  pub primary_beta       : u16, 
828  /// DEPRECATED, won't get serialized
829  /// reconstructed primary charge
830  pub primary_charge     : u16, 
831  /// scalar number of hits missed in
832  /// this event due to DRS on the RB
833  /// being busy
834  pub drs_dead_lost_hits : u16, 
835  pub dsi_j_mask         : u32,
836  pub channel_mask       : Vec<u16>,
837  pub mtb_link_mask      : u64,
838  pub hits               : Vec<TofHit>,
839  // a bunch of calculated variablels, used 
840  // for online interesting event search
841  // these will be only available in ProtocolVersion 1
842  pub n_hits_umb         : u8,
843  pub n_hits_cbe         : u8,
844  pub n_hits_cor         : u8,
845  pub tot_edep_umb       : f32,
846  pub tot_edep_cbe       : f32,
847  pub tot_edep_cor       : f32,
848  pub paddles_set        : bool,
849}
850
851impl TofEventSummary {
852
853  pub fn new() -> Self {
854    Self {
855      status             : EventStatus::Unknown,
856      version            : ProtocolVersion::Unknown,
857      n_hits_umb         : 0,
858      n_hits_cbe         : 0,
859      n_hits_cor         : 0,
860      tot_edep_umb       : 0.0,
861      tot_edep_cbe       : 0.0,
862      tot_edep_cor       : 0.0,
863      quality            : 0,
864      trigger_sources    : 0,
865      n_trigger_paddles  : 0,
866      event_id           : 0,
867      run_id             : 0,
868      timestamp32        : 0,
869      timestamp16        : 0,
870      primary_beta       : 0, 
871      primary_charge     : 0, 
872      drs_dead_lost_hits : 0,
873      dsi_j_mask         : 0,
874      channel_mask       : Vec::<u16>::new(),
875      mtb_link_mask      : 0,
876      hits               : Vec::<TofHit>::new(),
877      paddles_set        : false,
878    }
879  }
880  
881  #[cfg(feature="database")]
882  pub fn normalize_hit_times(&mut self) {
883    if self.hits.len() == 0 {
884      return;
885    }
886    let phase0 = self.hits[0].phase.to_f32();
887    for h in &mut self.hits {
888      let t0 = h.get_t0_uncorrected() + h.get_cable_delay();
889      let mut phase_diff = h.phase.to_f32() - phase0;
890      while phase_diff < - PI/2.0 {
891        phase_diff += 2.0*PI;
892      }
893      while phase_diff > PI/2.0 {
894        phase_diff -= 2.0*PI;
895      }
896      let t_shift = 50.0*phase_diff/(2.0*PI);
897      h.event_t0 = t0 + t_shift;
898    }
899  }
900 
901  #[cfg(feature="database")]
902  pub fn set_paddles(&mut self, paddles : &HashMap<u8, Paddle>) {
903    let mut nerror = 0u8;
904    for h in &mut self.hits {
905      match paddles.get(&h.paddle_id) {
906        None => {
907          error!("Got paddle id {} which is not in given map!", h.paddle_id);
908          nerror += 1;
909          continue;
910        }
911        Some(pdl) => {
912          h.set_paddle(pdl);
913        }
914      }
915    }
916    if nerror == 0 {
917      self.paddles_set = true;
918    }
919  }
920
921  /// Get the pointcloud of this event, sorted by time
922  /// 
923  /// # Returns
924  ///   (f32, f32, f32, f32, f32) : (x,y,z,t,edep)
925  pub fn get_pointcloud(&self) -> Option<Vec<(f32,f32,f32,f32,f32)>> {
926    let mut pc = Vec::<(f32,f32,f32,f32,f32)>::new();
927    if !self.paddles_set {
928      error!("Before getting the pointcloud, paddle information needs to be set for this event. Call TofEventSummary;:set_paddle");
929      return None;
930    }
931    for h in &self.hits {
932      let result = (h.x, h.y, h.z, h.get_t0(), h.get_edep());
933      pc.push(result);
934    }
935    Some(pc)
936  }
937
938  /// Compare the MasterTriggerEvent::trigger_hits with 
939  /// the actual hits to determine from which paddles
940  /// we should have received HG hits (from waveforms)
941  /// but we did not get them
942  ///
943  /// WARNING: The current implementation of this is 
944  /// rather slow and not fit for production use
945  /// FIXME - rewrite as a closure
946  #[cfg(feature="database")]
947  pub fn get_missing_paddles_hg(&self, pid_map :   &DsiJChPidMapping) -> Vec<u8> {
948    let mut missing = Vec::<u8>::new();
949    for th in self.get_trigger_hits() {
950      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
951      let mut found = false;
952      for h in &self.hits {
953        if h.paddle_id == pid {
954          found = true;
955          break
956        }
957      }
958      if !found {
959        missing.push(pid);
960      }
961    }
962    missing
963  }
964  
965  /// Get the triggered paddle ids
966  ///
967  /// Warning, this might be a bit slow
968  #[cfg(feature="database")]
969  pub fn get_triggered_paddles(&self, pid_map :   DsiJChPidMapping) -> Vec<u8> {
970    let mut paddles = Vec::<u8>::new();
971    for th in self.get_trigger_hits() {
972      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
973      paddles.push(pid);
974    }
975    paddles
976  }
977
978  /// Get the RB link IDs according to the mask
979  pub fn get_rb_link_ids(&self) -> Vec<u8> {
980    let mut links = Vec::<u8>::new();
981    for k in 0..64 {
982      if (self.mtb_link_mask >> k) as u64 & 0x1 == 1 {
983        links.push(k as u8);
984      }
985    }
986    links
987  }
988
989  /// Get the combination of triggered DSI/J/CH on 
990  /// the MTB which formed the trigger. This does 
991  /// not include further hits which fall into the 
992  /// integration window. For those, se rb_link_mask
993  ///
994  /// The returned values follow the TOF convention
995  /// to start with 1, so that we can use them to 
996  /// look up LTB ids in the db.
997  ///
998  /// # Returns
999  ///
1000  ///   Vec<(hit)> where hit is (DSI, J, CH) 
1001  pub fn get_trigger_hits(&self) -> Vec<(u8, u8, (u8, u8), LTBThreshold)> {
1002    let mut hits = Vec::<(u8,u8,(u8,u8),LTBThreshold)>::with_capacity(5); 
1003    let physical_channels = [(1u8,  2u8), (3u8,4u8), (5u8, 6u8), (7u8, 8u8),
1004                             (9u8, 10u8), (11u8,12u8), (13u8, 14u8), (15u8, 16u8)];
1005    //let n_masks_needed = self.dsi_j_mask.count_ones() / 2 + self.dsi_j_mask.count_ones() % 2;
1006    let n_masks_needed = self.dsi_j_mask.count_ones();
1007    if self.channel_mask.len() < n_masks_needed as usize {
1008      error!("We need {} hit masks, but only have {}! This is bad!", n_masks_needed, self.channel_mask.len());
1009      return hits;
1010    }
1011    let mut n_mask = 0;
1012    trace!("Expecting {} hit masks", n_masks_needed);
1013    trace!("ltb channels {:?}", self.dsi_j_mask);
1014    trace!("hit masks {:?}", self.channel_mask); 
1015    //println!("We see LTB Channels {:?} with Hit masks {:?} for {} masks requested by us!", self.dsi_j_mask, self.channel_mask, n_masks_needed);
1016    
1017    // one k here is for one ltb
1018    for k in 0..32 {
1019      if (self.dsi_j_mask >> k) as u32 & 0x1 == 1 {
1020        let mut dsi = 0u8;
1021        let mut j   = 0u8;
1022        if k < 5 {
1023          dsi = 1;
1024          j   = k as u8 + 1;
1025        } else if k < 10 {
1026          dsi = 2;
1027          j   = k as u8 - 5 + 1;
1028        } else if k < 15 {
1029          dsi = 3;
1030          j   = k as u8- 10 + 1;
1031        } else if k < 20 {
1032          dsi = 4;
1033          j   = k as u8- 15 + 1;
1034        } else if k < 25 {
1035          dsi = 5;
1036          j   = k as u8 - 20 + 1;
1037        } 
1038        //let dsi = (k as f32 / 4.0).floor() as u8 + 1;       
1039        //let j   = (k % 5) as u8 + 1;
1040        //println!("n_mask {n_mask}");
1041        let channels = self.channel_mask[n_mask]; 
1042        for (i,ch) in LTB_CHANNELS.iter().enumerate() {
1043          //let chn = *ch as u8 + 1;
1044          let ph_chn = physical_channels[i];
1045          //let chn = i as u8 + 1;
1046          //println!("i,ch {}, {}", i, ch);
1047          let thresh_bits = ((channels & ch) >> (i*2)) as u8;
1048          //println!("thresh_bits {}", thresh_bits);
1049          if thresh_bits > 0 { // hit over threshold
1050            hits.push((dsi, j, ph_chn, LTBThreshold::from(thresh_bits)));
1051          }
1052        }
1053        n_mask += 1;
1054      } // next ltb
1055    }
1056    hits
1057  }
1058  
1059  /// Get the trigger sources from trigger source byte
1060  pub fn get_trigger_sources(&self) -> Vec<TriggerType> {
1061    transcode_trigger_sources(self.trigger_sources)
1062  }
1063  
1064  pub fn get_timestamp48(&self) -> u64 {
1065    ((self.timestamp16 as u64) << 32) | self.timestamp32 as u64
1066  }
1067  
1068  /// Ttotal energy depostion in the TOF - Umbrella
1069  ///
1070  /// Utilizes Philip's formula based on 
1071  /// peak height
1072  pub fn get_edep_umbrella(&self) -> f32 {
1073    let mut tot_edep = 0.0f32;
1074    for h in &self.hits {
1075      if h.paddle_id < 61 || h.paddle_id > 108 {
1076        continue;
1077      }
1078      tot_edep += h.get_edep();
1079    }
1080    tot_edep
1081  }
1082  
1083  /// Ttotal energy depostion in the TOF - Umbrella
1084  ///
1085  /// Utilizes Philip's formula based on 
1086  /// peak height
1087  pub fn get_edep_cube(&self) -> f32 {
1088    let mut tot_edep = 0.0f32;
1089    for h in &self.hits {
1090      if h.paddle_id > 60 {
1091        continue;
1092      }
1093      tot_edep += h.get_edep();
1094    }
1095    tot_edep
1096  }
1097  
1098  /// Ttotal energy depostion in the Cortina
1099  ///
1100  /// Utilizes Philip's formula based on 
1101  /// peak height
1102  pub fn get_edep_cortina(&self) -> f32 {
1103    let mut tot_edep = 0.0f32;
1104    for h in &self.hits {
1105      if h.paddle_id < 109 {
1106        continue;
1107      }
1108      tot_edep += h.get_edep();
1109    }
1110    tot_edep
1111  }
1112  
1113  /// Ttotal energy depostion in the complete TOF
1114  ///
1115  /// Utilizes Philip's formula based on 
1116  /// peak height
1117  pub fn get_edep(&self) -> f32 {
1118    let mut tot_edep = 0.0f32;
1119    for h in &self.hits {
1120      tot_edep += h.get_edep();
1121    }
1122    tot_edep
1123  }
1124
1125  pub fn get_nhits_umb(&self) -> usize {
1126    let mut nhit = 0;
1127    for h in &self.hits {
1128      if h.paddle_id > 60 && h.paddle_id < 109 {
1129        nhit += 1;
1130      }
1131    }
1132    nhit
1133  }
1134
1135  pub fn get_nhits(&self) -> usize {
1136    self.hits.len()
1137  }
1138
1139  /// Allows to get TofEventSummary from a packet 
1140  /// of type TofEvent. This will dismiss all the 
1141  /// waveforms and RBEvents
1142  pub fn from_tofeventpacket(pack : &TofPacket)
1143    -> Result<Self, SerializationError> {
1144    if pack.packet_type != PacketType::TofEvent {
1145      return Err(SerializationError::IncorrectPacketType);
1146    }
1147    let mut pos = 0usize;
1148    let stream  = &pack.payload;
1149    let head    = parse_u16(stream, &mut pos);
1150    if head != TofEvent::HEAD {
1151      return Err(SerializationError::HeadInvalid);
1152    }
1153    let mut te           = TofEvent::new();
1154    te.compression_level = CompressionLevel::try_from(parse_u8(stream, &mut pos)).unwrap();
1155    te.quality           = EventQuality::try_from(parse_u8(stream, &mut pos)).unwrap();
1156    te.header            = TofEventHeader::from_bytestream(stream, &mut pos)?;
1157    te.mt_event          = MasterTriggerEvent::from_bytestream(stream, &mut pos)?;
1158    
1159    let v_sizes              = TofEvent::decode_size_header(&parse_u32(stream, &mut pos));
1160    for k in 0..v_sizes.0 {
1161      match RBEvent::from_bytestream_nowaveforms(stream, &mut pos) {
1162        Err(err) => error!("Expected RBEvent {} of {}, but got serialization error {}!", k,  v_sizes.0, err),
1163        Ok(ev) => {
1164          te.rb_events.push(ev);
1165        }
1166      }
1167    }
1168    let tail = parse_u16(stream, &mut pos);
1169    if tail != Self::TAIL {
1170      error!("Decoding of TAIL failed! Got {} instead!", tail);
1171      return Err(SerializationError::TailInvalid);
1172    }
1173    let summary = te.get_summary();
1174    return Ok(summary);
1175  }
1176}
1177
1178impl Packable for TofEventSummary {
1179  const PACKET_TYPE        : PacketType = PacketType::TofEventSummary;
1180}
1181
1182impl Serialization for TofEventSummary {
1183  
1184  const HEAD               : u16   = 43690; //0xAAAA
1185  const TAIL               : u16   = 21845; //0x5555
1186  
1187  fn to_bytestream(&self) -> Vec<u8> {
1188    let mut stream = Vec::<u8>::new();
1189    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
1190    let status_version = self.status.to_u8() | self.version.to_u8();
1191    stream.push(status_version);
1192    stream.extend_from_slice(&self.trigger_sources.to_le_bytes());
1193    stream.extend_from_slice(&self.n_trigger_paddles.to_le_bytes());
1194    stream.extend_from_slice(&self.event_id.to_le_bytes());
1195    // depending on the version, we send the fc event packet
1196    if self.version == ProtocolVersion::V1 {
1197      stream.extend_from_slice(&self.n_hits_umb  .to_le_bytes()); 
1198      stream.extend_from_slice(&self.n_hits_cbe  .to_le_bytes()); 
1199      stream.extend_from_slice(&self.n_hits_cor  .to_le_bytes()); 
1200      stream.extend_from_slice(&self.tot_edep_umb.to_le_bytes()); 
1201      stream.extend_from_slice(&self.tot_edep_cbe.to_le_bytes()); 
1202      stream.extend_from_slice(&self.tot_edep_cor.to_le_bytes()); 
1203    }
1204    stream.extend_from_slice(&self.quality.to_le_bytes());
1205    stream.extend_from_slice(&self.timestamp32.to_le_bytes());
1206    stream.extend_from_slice(&self.timestamp16.to_le_bytes());
1207    //stream.extend_from_slice(&self.primary_beta.to_le_bytes());
1208    stream.extend_from_slice(&self.run_id.to_le_bytes());
1209    stream.extend_from_slice(&self.drs_dead_lost_hits.to_le_bytes());
1210    //stream.extend_from_slice(&self.primary_charge.to_le_bytes());
1211    stream.extend_from_slice(&self.dsi_j_mask.to_le_bytes());
1212    let n_channel_masks = self.channel_mask.len();
1213    stream.push(n_channel_masks as u8);
1214    for k in 0..n_channel_masks {
1215      stream.extend_from_slice(&self.channel_mask[k].to_le_bytes());
1216    }
1217    stream.extend_from_slice(&self.mtb_link_mask.to_le_bytes());
1218    let nhits = self.hits.len() as u16;
1219    stream.extend_from_slice(&nhits.to_le_bytes());
1220    for k in 0..self.hits.len() {
1221      stream.extend_from_slice(&self.hits[k].to_bytestream());
1222    }
1223    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
1224    stream
1225  }
1226  
1227  fn from_bytestream(stream    : &Vec<u8>, 
1228                     pos       : &mut usize) 
1229    -> Result<Self, SerializationError>{
1230    let mut summary           = Self::new();
1231    let head = parse_u16(stream, pos);
1232    if head != Self::HEAD {
1233      error!("Decoding of HEAD failed! Got {} instead!", head);
1234      return Err(SerializationError::HeadInvalid);
1235    }
1236    let status_version_u8     = parse_u8(stream, pos);
1237    let status                = EventStatus::from(status_version_u8 & 0x3f);
1238    let version               = ProtocolVersion::from(status_version_u8 & 0xc0); 
1239    summary.status            = status;
1240    summary.version           = version;
1241    summary.trigger_sources   = parse_u16(stream, pos);
1242    summary.n_trigger_paddles = parse_u8(stream, pos);
1243    summary.event_id          = parse_u32(stream, pos);
1244    if summary.version == ProtocolVersion::V1 {
1245      summary.n_hits_umb      = parse_u8(stream, pos); 
1246      summary.n_hits_cbe      = parse_u8(stream, pos); 
1247      summary.n_hits_cor      = parse_u8(stream, pos); 
1248      summary.tot_edep_umb    = parse_f32(stream, pos); 
1249      summary.tot_edep_cbe    = parse_f32(stream, pos); 
1250      summary.tot_edep_cor    = parse_f32(stream, pos); 
1251    }
1252    summary.quality            = parse_u8(stream, pos);
1253    summary.timestamp32        = parse_u32(stream, pos);
1254    summary.timestamp16        = parse_u16(stream, pos);
1255    summary.run_id             = parse_u16(stream, pos);
1256    summary.drs_dead_lost_hits = parse_u16(stream, pos);
1257    summary.dsi_j_mask         = parse_u32(stream, pos);
1258    let n_channel_masks        = parse_u8(stream, pos);
1259    for _ in 0..n_channel_masks {
1260      summary.channel_mask.push(parse_u16(stream, pos));
1261    }
1262    summary.mtb_link_mask     = parse_u64(stream, pos);
1263    let nhits                 = parse_u16(stream, pos);
1264    for _ in 0..nhits {
1265      summary.hits.push(TofHit::from_bytestream(stream, pos)?);
1266    }
1267    let tail = parse_u16(stream, pos);
1268    if tail != Self::TAIL {
1269      error!("Decoding of TAIL failed for version {}! Got {} instead!", version, tail);
1270      return Err(SerializationError::TailInvalid);
1271    }
1272    Ok(summary)
1273  }
1274}
1275    
1276impl Default for TofEventSummary {
1277  fn default() -> Self {
1278    Self::new()
1279  }
1280}
1281
1282impl fmt::Display for TofEventSummary {
1283  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1284    let mut repr = format!("<TofEventSummary (version {})", self.version);
1285    repr += &(format!("\n  EventID          : {}", self.event_id));
1286    repr += &(format!("\n  RunID            : {}", self.run_id));
1287    repr += &(format!("\n  EventStatus      : {}", self.status));
1288    repr += &(format!("\n  TriggerSources   : {:?}", self.get_trigger_sources()));
1289    repr += &(format!("\n  NTrigPaddles     : {}", self.n_trigger_paddles));
1290    repr += &(format!("\n  DRS dead hits    : {}", self.drs_dead_lost_hits));
1291    repr += &(format!("\n  timestamp32      : {}", self.timestamp32)); 
1292    repr += &(format!("\n  timestamp16      : {}", self.timestamp16)); 
1293    repr += &(format!("\n   |-> timestamp48 : {}", self.get_timestamp48())); 
1294    //repr += &(format!("\n  PrimaryBeta      : {}", self.get_beta())); 
1295    //repr += &(format!("\n  PrimaryCharge    : {}", self.primary_charge));
1296    repr += &(format!("\n  ** ** TRIGGER HITS (DSI/J/CH) [{} LTBS] ** **", self.dsi_j_mask.count_ones()));
1297    for k in self.get_trigger_hits() {
1298      repr += &(format!("\n  => {}/{}/({},{}) ({}) ", k.0, k.1, k.2.0, k.2.1, k.3));
1299    }
1300    repr += "\n  ** ** MTB LINK IDs ** **";
1301    let mut mtblink_str = String::from("\n  => ");
1302    for k in self.get_rb_link_ids() {
1303      mtblink_str += &(format!("{} ", k))
1304    }
1305    repr += &mtblink_str;
1306    repr += &(format!("\n  == Trigger hits {}, expected RBEvents {}",
1307            self.get_trigger_hits().len(),
1308            self.get_rb_link_ids().len()));
1309    repr += &String::from("\n  ** ** ** HITS ** ** **");
1310    for h in &self.hits {
1311      repr += &(format!("\n  {}", h));
1312    }
1313    write!(f, "{}", repr)
1314  }
1315}
1316
1317#[cfg(feature="random")]
1318impl FromRandom for TofEventSummary {
1319
1320  fn from_random() -> Self {
1321    let mut summary           = Self::new();
1322    let mut rng               = rand::thread_rng();
1323    let status                = EventStatus::from_random();
1324    let version               = ProtocolVersion::from_random();
1325    if version == ProtocolVersion::V1 {
1326      summary.n_hits_umb        = rng.gen::<u8>();
1327      summary.n_hits_cbe        = rng.gen::<u8>();
1328      summary.n_hits_cor        = rng.gen::<u8>();
1329      summary.tot_edep_umb      = rng.gen::<f32>();
1330      summary.tot_edep_cbe      = rng.gen::<f32>();
1331      summary.tot_edep_cor      = rng.gen::<f32>();
1332      summary.quality           = rng.gen::<u8>();
1333    }
1334    summary.status             = status;
1335    summary.version            = version;
1336    // variable packet for the FC
1337    summary.trigger_sources    = rng.gen::<u16>();
1338    summary.n_trigger_paddles  = rng.gen::<u8>();
1339    summary.event_id           = rng.gen::<u32>();
1340    summary.timestamp32        = rng.gen::<u32>();
1341    summary.timestamp16        = rng.gen::<u16>();
1342    summary.drs_dead_lost_hits = rng.gen::<u16>();
1343    summary.dsi_j_mask         = rng.gen::<u32>();
1344    let n_channel_masks        = rng.gen::<u8>();
1345    for _ in 0..n_channel_masks {
1346      summary.channel_mask.push(rng.gen::<u16>());
1347    }
1348    summary.mtb_link_mask      = rng.gen::<u64>();
1349    //let nhits                  = rng.gen::<u8>();
1350    let nhits = 1;
1351    for _ in 0..nhits {
1352      summary.hits.push(TofHit::from_random());
1353    }
1354    summary
1355  }
1356}
1357
1358//
1359// TESTS
1360//
1361// ============================================
1362
1363#[test]
1364fn packable_tofeventsummary() {
1365  for _ in 0..100 {
1366    let data = TofEventSummary::from_random();
1367    let mut test : TofEventSummary = data.pack().unpack().unwrap();
1368    //println!("{}", data.hits[0]);
1369    //println!("{}", test.hits[0]);
1370    // Manually zero these fields, since comparison with nan will fail and 
1371    // from_random did not touch these
1372    for h in &mut test.hits {
1373      h.paddle_len       = 0.0; 
1374      h.cable_len        = 0.0; 
1375      h.coax_cable_time  = 0.0; 
1376      h.hart_cable_time  = 0.0; 
1377      h.x                = 0.0; 
1378      h.y                = 0.0; 
1379      h.z                = 0.0; 
1380      h.event_t0         = 0.0;
1381    }
1382    assert_eq!(data, test);
1383  }
1384}  
1385
1386#[test]
1387fn emit_tofeventsummary() {
1388  for _ in 0..100 {
1389    let data = TofEvent::from_random();
1390    let summary = data.get_summary();
1391    let test : TofEventSummary = summary.pack().unpack().unwrap();
1392    assert_eq!(summary, test);
1393  }
1394}
1395
1396#[test]
1397#[cfg(feature = "random")]
1398fn tofevent_sizes_header() {
1399  for _ in 0..100 {
1400    let data = TofEvent::from_random();
1401    let mask = data.construct_sizes_header();
1402    let size = TofEvent::decode_size_header(&mask);
1403    assert_eq!(size.0, data.rb_events.len());
1404    //assert_eq!(size.1, data.missing_hits.len());
1405  }
1406}
1407
1408#[test]
1409#[cfg(feature = "random")]
1410fn packable_tofevent() {
1411  for _ in 0..5 {
1412    let data = TofEvent::from_random();
1413    let test : TofEvent = data.pack().unpack().unwrap();
1414    assert_eq!(data.header, test.header);
1415    assert_eq!(data.compression_level, test.compression_level);
1416    assert_eq!(data.quality, test.quality);
1417    assert_eq!(data.mt_event, test.mt_event);
1418    assert_eq!(data.rb_events.len(), test.rb_events.len());
1419    //assert_eq!(data.missing_hits.len(), test.missing_hits.len());
1420    //assert_eq!(data.missing_hits, test.missing_hits);
1421    assert_eq!(data.rb_events, test.rb_events);
1422    //assert_eq!(data, test);
1423    //println!("{}", data);
1424  }
1425}
1426
1427#[test]
1428#[cfg(feature = "random")]
1429fn serialize_tofeventheader() {
1430  let data = TofEventHeader::from_random();
1431  let test = TofEventHeader::from_bytestream(&data.to_bytestream(), &mut 0).unwrap();
1432  assert_eq!(data, test);
1433}
1434