1use crate::prelude::*;
7
8#[cfg_attr(feature="pybindings", pyclass)]
21#[derive(Debug, Clone, PartialEq)]
22pub struct TelemetryEvent {
23 pub header : TelemetryPacketHeader,
24 pub creation_time : u64,
25 pub event_id : u32,
26 pub tracker_hits : Vec<TrackerHit>,
27 pub tracker_oscillators : Vec<u64>,
28 pub tof_event : TofEvent,
29 pub raw_data : Vec<u8>,
34 pub flags0 : u8,
35 pub flags1 : u8,
36 pub version : u8,
37 pub osc_flags : u8,
38 pub oscillator_idx : Vec<u8>,
39 pub expected_tr_hits : u8,
41}
42
43impl TelemetryEvent {
44
45 pub fn new() -> Self {
46 let mut tracker_oscillators = Vec::<u64>::new();
47 for _ in 0..10 {
48 tracker_oscillators.push(0);
49 }
50 Self {
51 header : TelemetryPacketHeader::new(),
52 creation_time : 0,
53 event_id : 0,
54 tracker_hits : Vec::<TrackerHit>::new(),
55 tracker_oscillators : tracker_oscillators,
56 tof_event : TofEvent::new(),
57 raw_data : Vec::<u8>::new(),
58 flags0 : 0,
59 flags1 : 1,
60 version : 0,
61 osc_flags : 0,
62 oscillator_idx : Vec::<u8>::new(),
63 expected_tr_hits : 0,
64 }
65 }
66
67 pub fn pack(&self) -> TelemetryPacket {
73 let mut tp = TelemetryPacket::new();
74 tp.header = self.header.clone();
77 tp.payload = self.to_bytestream();
78 tp
79 }
80
81 pub fn calibrate_trk_hits(&mut self, cali : &TrackerOfflineCalibration)
82 -> Result<(), CalibrationError> {
83 cali.mask_hits(&mut self.tracker_hits);
84 cali.calibrate(&mut self.tracker_hits)?;
85 Ok(())
86 }
87
88 #[cfg(feature="database")]
90 pub fn hydrate(&mut self, tof_paddles : &HashMap<u8,TofPaddle>, trk_strips : &HashMap<u32, TrackerStrip>) {
91 self.tof_event.set_paddles(tof_paddles);
92 for h in &mut self.tracker_hits {
93 h.set_coordinates(trk_strips);
94 }
95 }
96
97 pub fn delete_all_tracker_hits(&mut self) {
100 self.tracker_hits.clear();
101 }
102
103 pub fn add_tracker_hits(&mut self, hits: &Vec<TrackerHit>) {
105 self.tracker_hits.extend_from_slice(hits);
106 self.header.length += (4*hits.len()) as u16;
108 }
109
110 #[cfg(feature="database")]
111 pub fn mask_strips(&mut self, masks : &HashMap<u32, TrackerStripMask>) {
112 let mut clean_hits = Vec::<TrackerHit>::with_capacity(self.tracker_hits.len());
113 for h in &self.tracker_hits {
114 if !masks.contains_key(&h.get_stripid()) {
115 warn!("We don't have a mask information for strip id {}", h.get_stripid());
116 continue;
117 }
118 if masks[&h.get_stripid()].active {
119 clean_hits.push(h.clone());
120 }
121 }
122 self.tracker_hits = clean_hits;
123 }
124
125
126 }
223
224
225impl TelemetryPackable for TelemetryEvent {
226 }
229
230impl Serialization for TelemetryEvent {
231
232 fn from_bytestream(stream : &Vec<u8>,
233 pos : &mut usize)
234 -> Result<Self, SerializationError> {
235 let mut me = Self::new();
236 let version = parse_u8(stream, pos);
237 me.version = version;
238 me.flags0 = parse_u8(stream, pos);
239 if version == 0 {
242 me.flags1 = parse_u8(stream, pos);
243 } else {
244 *pos += 8;
245 }
246
247 me.event_id = parse_u32(stream, pos);
248 let _tof_delim = parse_u8(stream, pos);
250 if stream.len() <= *pos + 2 {
252 error!("Not able to parse merged event!");
253 return Err(SerializationError::StreamTooShort);
254 }
255 let num_tof_bytes = parse_u16(stream, pos) as usize;
256 if stream.len() < *pos+num_tof_bytes {
258 error!("Not enough bytes for TOF packet with {} bytes! Only {} bytes remaining in input", num_tof_bytes, stream.len() - *pos);
259 return Err(SerializationError::StreamTooShort);
260 }
261 let pos_before = *pos;
262 if num_tof_bytes != 0 {
263 let tof_pack = TofPacket::from_bytestream(stream, pos)?;
264 let ts = tof_pack.unpack::<TofEvent>()?;
265 me.tof_event = ts;
267 }
268 if pos_before + num_tof_bytes != *pos {
269 error!("Byte misalignment. Expected {num_tof_bytes}, got {pos} - {pos_before}");
270 return Err(SerializationError::WrongByteSize);
271 }
272 let trk_delim = parse_u8(stream, pos);
273
274 if trk_delim != 0xbb {
276 return Err(SerializationError::HeadInvalid);
277 }
278 if version == 1 {
279 let num_trk_hits = parse_u16(stream, pos);
280 if (*pos + (num_trk_hits as usize)*4 ) > stream.len() {
281 let expected_s = *pos + (num_trk_hits as usize)*4 - stream.len();
282 let actual = stream.len() - *pos;
283 error!("We expect {} more bytes, but see only {}", expected_s, actual);
284 error!("Not enough bytes ({}) for {} tracker hits!", stream.len(), num_trk_hits);
285 return Err(SerializationError::StreamTooShort);
287 }
288 for _ in 0..num_trk_hits {
289 let mut hit = TrackerHit::new();
290 let strip_id = parse_u16(stream, pos);
291 let adc = parse_u16(stream, pos);
292 hit.channel = (strip_id & 0b11111) as u8;
293 hit.module = ((strip_id >> 5) & 0b111) as u8;
294 hit.row = ((strip_id >> 8) & 0b111) as u8;
295 hit.layer = ((strip_id >> 11) & 0b1111) as u8;
296 hit.adc = adc;
297 me.tracker_hits.push(hit);
298 }
299 let oscillators_delimiter = parse_u8(stream, pos);
301 if oscillators_delimiter != 0xcc {
302 return Err(SerializationError::HeadInvalid);
303 }
304 me.osc_flags = parse_u8(stream, pos);
305 let mut oscillator_idx = Vec::<u8>::new();
306 for j in 0..8 {
307 if (me.osc_flags >> j & 0b1) > 0 {
308 oscillator_idx.push(j)
309 }
310 }
311 if (*pos + oscillator_idx.len()*6) > stream.len() {
312 error!("Not enough bytes to parse tracker oscillators!");
313 return Err(SerializationError::StreamTooShort);
314 }
315 for idx in oscillator_idx.iter() {
316 let lower = parse_u32(stream, pos);
317 let upper = parse_u16(stream, pos);
318 let osc : u64 = (upper as u64) << 32 | (lower as u64);
319 me.tracker_oscillators[*idx as usize] = osc;
321 }
322 me.oscillator_idx = oscillator_idx;
323 } else if version == 0 {
324 error!("Unsupported {version}!");
325 return Err(SerializationError::UnsupportedVersion);
326 } else {
327 error!("Unsuported version {version}!");
328 return Err(SerializationError::UnsupportedVersion);
329 }
330 me.expected_tr_hits = me.tracker_hits.len() as u8;
331 Ok(me)
332 }
333
334 fn to_bytestream(&self) -> Vec<u8> {
335 let mut stream = Vec::<u8>::new();
336 stream.push(self.version);
337 stream.push(self.flags0);
338 if self.version == 0 {
339 stream.push(self.flags1);
340 } else {
341 stream.extend_from_slice(&[0u8;8]);
342 }
343 stream.extend_from_slice(&self.event_id.to_le_bytes());
344 stream.push(0xaa); let tof = self.tof_event.pack();
346 let tof_bytes = tof.to_bytestream();
347 let num_tof_bytes = tof_bytes.len() as u16;
348 debug!("Will write {} bytes for tef event to stream!", num_tof_bytes);
349 stream.extend_from_slice(&num_tof_bytes.to_le_bytes());
350 stream.extend_from_slice(&tof_bytes);
351 stream.push(0xbb);
352 stream.extend_from_slice(&(self.tracker_hits.len() as u16).to_le_bytes());
353 for h in &self.tracker_hits {
355 let mut strip_id: u16 = 0;
356 strip_id |= (h.channel as u16) & 0b11111; strip_id |= ((h.module as u16) & 0b111) << 5; strip_id |= ((h.row as u16) & 0b111) << 8; strip_id |= ((h.layer as u16) & 0b1111) << 11;
361 stream.extend_from_slice(&strip_id.to_le_bytes());
362 stream.extend_from_slice(&h.adc.to_le_bytes());
363 }
364 stream.push(0xcc); stream.push(self.osc_flags);
366 for idx in &self.oscillator_idx {
367 let osc = self.tracker_oscillators[*idx as usize];
370 let upper = ((osc >> 32) & (u16::MAX as u64)) as u16;
371 let lower = (osc & (u32::MAX as u64)) as u32;
372 stream.extend_from_slice(&lower.to_le_bytes());
374 stream.extend_from_slice(&upper.to_le_bytes());
375 }
376 return stream;
377 }
378}
379
380impl fmt::Display for TelemetryEvent {
381 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382 let mut repr = String::from("<TelemetryEvent:");
383 let mut te = self.tof_event.clone();
384 te.calc_gcu_variables();
385 let tof_str = format!("\n {}", self.tof_event);
386 let mut good_hits = 0;
387
388 if self.version == 0 {
389 repr += "\n VERSION 0 NOT SUPPORTED!!";
390 } else if self.version == 1 {
391 for _ in &self.tracker_hits {
392 good_hits += 1;
393 }
394 }
395 repr += &(format!(" {}", self.header));
396 repr += "\n ** ** ** MERGED ** ** **";
397 repr += &(format!("\n version {}", self.version));
398 repr += &(format!("\n event ID {}", self.event_id));
399 repr += "\n ** ** ** TOF GCU VARIABLES ** ** **";
400 repr += &(format!("\n n_hits_umb {}", te.n_hits_umb));
401 repr += &(format!("\n n_hits_cbe {}", te.n_hits_cbe));
402 repr += &(format!("\n n_hits_cor {}", te.n_hits_cor));
403 repr += &(format!("\n tot_edep_umb {}", te.tot_edep_umb));
404 repr += &(format!("\n tot_edep_cbe {}", te.tot_edep_cbe));
405 repr += &(format!("\n tot_edep_cor {}", te.tot_edep_cor));
406 if self.version == 0 {
407 repr += "\n VERSION 0 NOT SUPPORTED!!";
408 }
409 repr += "\n ** ** ** TRACKER ** ** **";
410 if self.version == 0 {
411 repr += "\n VERSION 0 NOT SUPPORTED!!";
412 } else if self.version == 1 {
413 repr += &(format!("\n Trk oscillators {:?}", self.tracker_oscillators));
414 }
415 repr += &(format!("\n N Good Trk Hits {}", good_hits));
416 repr += &tof_str;
417 write!(f,"{}", repr)
418 }
419}
420
421#[cfg(feature="pybindings")]
424#[pymethods]
425impl TelemetryEvent {
426
427 #[getter]
428 #[pyo3(name="exptected_tracker_hits")]
429 fn excpected_trk_hits_py(&self) -> u8 {
430 self.expected_tr_hits
431 }
432
433 #[getter]
434 #[pyo3(name="has_at_least_expected_trk_hits")]
435 fn has_at_least_expected_trk_hits(&self) -> bool {
436 return self.tracker_hits.len() as u8 >= self.expected_tr_hits
437 }
438
439 #[getter]
440 #[pyo3(name="version")]
441 fn version_py(&self) -> u8 {
442 self.version
443 }
444
445 #[getter]
446 #[pyo3(name="flags0")]
447 fn flags0_py(&self) -> u8 {
448 self.flags0
449 }
450
451 #[getter]
452 #[pyo3(name="flags1")]
453 fn flags1_py(&self) -> u8 {
454 self.flags1
455 }
456
457 #[getter]
464 fn get_header(&self) -> TelemetryPacketHeader {
465 self.header
466 }
467
468 #[getter]
469 fn tracker(&self) -> PyResult<Vec<TrackerHit>> {
470 Ok(self.tracker_hits.clone())
471 }
472
473 #[getter]
474 fn get_event_id(&self) -> u32 {
475 self.event_id
476 }
477
478 #[pyo3(name="tof_remove_non_causal_hits")]
483 fn tof_remove_non_causal_hits_py(&mut self) -> Vec<u16> {
484 let mut pids = Vec::<u16>::new();
487 for pid in self.tof_event.remove_non_causal_hits() {
488 pids.push(pid as u16);
489 }
490 pids
491 }
492
493 #[pyo3(name="tof_lightspeed_cleaning")]
501 pub fn tof_lightspeed_cleaning_py(&mut self, t_err : f32) -> (Vec<u16>, Vec<f32>) {
502 let mut pids = Vec::<u16>::new();
505 let (pids_rm, twindows) = self.tof_event.lightspeed_cleaning(t_err);
506 for pid in pids_rm {
507 pids.push(pid as u16);
508 }
509 (pids, twindows)
510 }
511
512 #[pyo3(name="set_tof_timing_offsets")]
519 pub fn set_tof_timing_offsets_py(&mut self, timing_offsets : HashMap<u8, f32>) {
520 self.tof_event.set_timing_offsets(&timing_offsets);
521 }
522
523 #[pyo3(name="tof_normalize_hit_times")]
527 pub fn tof_normalize_hit_times_py(&mut self) {
528 self.tof_event.normalize_hit_times();
529 }
530
531 #[getter]
534 fn get_tof(&self) -> PyResult<TofEvent> {
535 Ok(self.tof_event.clone())
536 }
537 #[getter]
563 fn tracker_pointcloud(&self) -> Vec<(f32, f32, f32, f32, f32)> {
564 let mut pts = Vec::<(f32,f32,f32,f32,f32)>::new();
565 for h in &self.tracker_hits {
566 let pt = (10.0*h.x, 10.0*h.y, 10.0*h.z, f32::NAN, h.adc as f32);
569 pts.push(pt);
570 }
571 pts
572 }
573
574 #[pyo3(name="add_tracker_hits")]
576 pub fn add_tracker_hits_py(&mut self, hits: Vec<TrackerHit>) {
577 self.tracker_hits.extend_from_slice(&hits);
579 self.header.length += (4*hits.len()) as u16;
581 }
582
583 #[pyo3(name="delete_all_tracker_hits")]
586 pub fn delete_all_tracker_hits_py(&mut self) {
587 self.tracker_hits.clear();
588 }
589
590 #[staticmethod]
594 fn from_telemetrypacket(packet : TelemetryPacket) -> PyResult<Self> {
595 match Self::from_bytestream(&packet.payload, &mut 0) {
596 Ok(mut event) => {
597 event.header = packet.header.clone();
598 #[cfg(feature="database")]
599 event.hydrate(&packet.tof_paddles, &packet.trk_strips);
600 return Ok(event);
601 }
602 Err(err) => {
603 return Err(PyValueError::new_err(err.to_string()));
604 }
605 }
606 }
607
608 #[pyo3(name="pack")]
609 fn pack_py(&self) -> TelemetryPacket {
610 self.pack()
611 }
612
613 #[pyo3(name="calibrate_trk_hits")]
614 fn calibrate_trk_hits_py(&mut self, cali : Bound<'_, TrackerOfflineCalibration> ) -> PyResult<()> {
615 let cali_ref = cali.borrow();
616 self.calibrate_trk_hits(&*cali_ref)?;
617 Ok(())
618 }
619
620}
637
638#[cfg(feature="random")]
639impl FromRandom for TelemetryEvent {
640
641 fn from_random() -> Self {
642 let mut rng = rand::rng();
643 let mut ev = Self::new();
644 ev.header = TelemetryPacketHeader::from_random();
645 ev.tof_event = TofEvent::from_random();
646 let n_trk_hits = 1u8;
648 for _ in 0..n_trk_hits {
649 let mut h = TrackerHit::from_random();
650 h.oscillator = 0;
651 h.asic_event_code = 0;
652 ev.tracker_hits.push(h);
653 }
654 ev.creation_time = 0;
656 ev.event_id = rng.random::<u32>();
657 ev.flags0 = 3;
658 ev.flags1 = 1;
659 ev.version = 1;
660 for idx in 0..10usize {
663 let active = rng.random::<bool>();
664 if idx < 8 && active {
665 ev.osc_flags = ev.osc_flags | (0b1 << idx);
666 let osc = rng.random::<u64>() & 0x0000FFFFFFFFFFFF;
667 ev.tracker_oscillators[idx] = osc;
668 ev.oscillator_idx.push(idx as u8);
669 }
671 }
672 return ev;
673 }
674}
675
676#[test]
677#[cfg(feature="random")]
678fn serialize_deserialize_telemetryevent() {
679 for _ in 0..10 {
680 let mut ev = TelemetryEvent::from_random();
681 let bytes = ev.to_bytestream();
682 let mut test = TelemetryEvent::from_bytestream(&bytes, &mut 0).unwrap();
683 let creation_time = Instant::now();
684 ev.tof_event.creation_time = creation_time;
685 test.tof_event.creation_time = creation_time;
686 ev.tof_event.rb_events.clear();
687 test.tof_event.rb_events.clear();
688 for h in &mut ev.tof_event.hits {
689 h.coax_cable_time = 0.0;
690 h.hart_cable_time = 0.0;
691 h.event_t0 = 0.0;
692 h.paddle_len = 0.0;
693 h.x = 0.0;
694 h.y = 0.0;
695 h.z = 0.0;
696 }
697 for h in &mut test.tof_event.hits {
698 h.coax_cable_time = 0.0;
699 h.hart_cable_time = 0.0;
700 h.event_t0 = 0.0;
701 h.paddle_len = 0.0;
702 h.x = 0.0;
703 h.y = 0.0;
704 h.z = 0.0;
705 }
706 assert_eq!(ev.creation_time , test.creation_time);
709 assert_eq!(ev.event_id , test.event_id);
710 assert_eq!(ev.osc_flags , test.osc_flags);
711 assert_eq!(ev.tracker_oscillators, test.tracker_oscillators);
712 assert_eq!(ev.raw_data , test.raw_data);
713 assert_eq!(ev.flags0 , test.flags0);
714 assert_eq!(ev.flags1 , test.flags1);
715 assert_eq!(ev.version , test.version);
716 assert_eq!(ev.oscillator_idx , test.oscillator_idx);
717 assert_eq!(ev.tracker_hits , test.tracker_hits);
718 assert_eq!(ev.tof_event , test.tof_event);
719 }
721}
722
723#[cfg(feature="pybindings")]
724pythonize!(TelemetryEvent);
725