go_pybindings/
telemetry.rs

1use std::collections::HashMap;
2
3use pyo3::prelude::*;
4use pyo3::exceptions::PyValueError;
5use pyo3::types::PyFunction;
6
7use std::fmt;
8
9//extern crate pyo3_log;
10//extern crate rpy-tof-dataclasses;
11
12use telemetry_dataclasses::packets as tel_api;
13use telemetry_dataclasses::io as tel_io_api;
14use crate::dataclasses::{
15  //PyTofHit,
16  PyTofEventSummary,
17};
18
19// FIXME - this needs to go to liftof-python
20// or maybe we want to revive the dataclasses pybindings
21// in tof-dataclasses?
22use tof_dataclasses::events as tof_api;
23
24#[pyclass]
25#[pyo3(name="TelemetryHeader")]
26pub struct PyTelemetryHeader {
27  header : tel_api::TelemetryHeader,
28}
29
30impl PyTelemetryHeader {
31  pub fn set_header(&mut self, header : tel_api::TelemetryHeader) {
32    self.header = header
33  }
34}
35
36#[pymethods]
37impl PyTelemetryHeader {
38  #[new]
39  fn new() -> Self {
40    Self {
41      header : tel_api::TelemetryHeader::new(),
42    }
43  }
44
45  /// Alex' special time convention
46  #[getter]
47  fn gcutime(&self) -> f64 {
48    self.header.get_gcutime()
49  }
50
51  /// Get the current packet count
52  /// 
53  /// (16bit number) so rollovers are 
54  /// expected
55  #[getter]
56  fn counter(&self) -> u16 { 
57    self.header.counter
58  } 
59
60  #[getter]
61  fn packet_type(&self) -> u8 {
62    self.header.ptype
63  }
64
65  /// GCU time of packet creation
66  #[getter]
67  fn timestamp(&self) -> u32 {
68    self.header.timestamp
69  }
70
71  /// The length of the following payload
72  #[getter]
73  fn length(&self) -> u16 {
74    self.header.length
75  }
76
77  fn __repr__(&self) -> PyResult<String> {
78    Ok(format!("<PyO3Wrapper: {}>", self.header))
79  }
80}
81
82#[pyclass]
83#[pyo3(name="MergedEvent")]
84pub struct PyMergedEvent {
85  pub event : tel_api::MergedEvent,
86}
87
88#[pymethods]
89impl PyMergedEvent {
90  #[new]
91  pub fn new() -> Self {
92    Self {
93      event : tel_api::MergedEvent::new(),
94    }
95  }
96
97  #[getter]
98  fn version(&self) -> u8 {
99    self.event.version
100  }
101  
102  #[getter]
103  fn event_id(&self) -> u32 {
104      self.event.event_id
105  }
106  #[getter]
107  fn tracker_v2(&self) -> PyResult<Vec<PyTrackerHitV2>> {
108    let mut hits = Vec::<PyTrackerHitV2>::new();
109    for h in &self.event.tracker_hitsv2 {
110      let mut pyhit = PyTrackerHitV2::new();
111      pyhit.set_hit(h.clone());
112      //pyhit.hit = h.clone();
113      hits.push(pyhit);
114    }
115    Ok(hits)
116  }
117
118  #[getter]
119  fn tracker_v1(&self) -> PyResult<Vec<PyTrackerEvent>> {
120    let mut events = Vec::<PyTrackerEvent>::new();
121    for k in &self.event.tracker_events {
122      let mut pytrk = PyTrackerEvent::new();
123      pytrk.set_event(k.clone());
124      events.push(pytrk);
125    }
126    Ok(events)
127  }
128
129  #[getter]
130  fn get_event_id(&self) -> u32 {
131    self.event.event_id
132  }
133
134  // FIXME - do this with bound
135  #[getter]
136  fn get_tof(&self) -> PyResult<PyTofEventSummary> {
137  //fn get_tof<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyTofEventSummary>> {
138    let mut pyts = PyTofEventSummary::new();
139    pyts.event   = self.event.tof_event.clone();
140    Ok(pyts)
141  }
142    //match TofPacket::from_bytestream(&self.event.tof_data, &mut 0) {
143    //  Err(err) => {
144    //    //error!("Unable to parse TofPacket! {err}");
145    //    return Err(PyValueError::new_err(err.to_string()));
146    //  }
147    //  Ok(pack) => {
148    //    match pack.unpack::<tof_api::TofEventSummary>() {
149    //      Err(err) => {
150    //        return Err(PyValueError::new_err(err.to_string()));
151    //        //error!("Unable to parse TofEventSummary! {err}");
152    //      }
153    //      Ok(ts)    => {
154    //        let mut pyts = PyTofEventSummary::new();
155    //        pyts.event = ts;
156    //        return Ok(pyts);
157    //      }
158    //    }
159    //  }
160    //}
161    //}
162
163  #[getter]
164  fn tracker_pointcloud(&self) -> Vec<(f32, f32, f32, f32, f32)> {
165    let mut pts = Vec::<(f32,f32,f32,f32,f32)>::new();
166    for h in &self.event.tracker_hitsv2 {
167      // uses adc
168      // FIXME - factor 10!
169      let pt = (10.0*h.x, 10.0*h.y, 10.0*h.z, f32::NAN, h.adc as f32);
170      pts.push(pt);
171    }
172    pts
173  }
174
175  /// Populate a merged event from a TelemetryPacket.
176  ///
177  /// Telemetry packet type should be 90 (MergedEvent)
178  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
179    match tel_api::MergedEvent::from_bytestream(&packet.packet.payload, &mut 0) {
180      Ok(event) => {
181        self.event = event;
182        self.event.header = packet.packet.header.clone();
183      }
184      Err(err) => {
185        return Err(PyValueError::new_err(err.to_string()));
186      }  
187    }
188    Ok(())
189  }
190  
191  fn __repr__(&self) -> PyResult<String> {
192    Ok(format!("<PyO3Wrapper: {}>", self.event))
193  }
194}
195
196#[pyclass]
197#[pyo3(name="TrackerHeader")]
198pub struct PyTrackerHeader {
199  header : tel_api::TrackerHeader,
200}
201
202impl PyTrackerHeader {
203  pub fn set_header(&mut self, header : tel_api::TrackerHeader) {
204    self.header = header;
205  }
206}
207
208#[pymethods]
209impl PyTrackerHeader {
210
211  #[new]
212  fn new() -> Self {
213    Self {
214      header : tel_api::TrackerHeader::new(),
215    }
216  }
217
218  #[getter]
219  fn sync     (&self) -> u16 {
220    self.header.sync
221  }
222
223  #[getter]
224  fn crc      (&self) -> u16 {
225    self.header.crc
226  }
227
228  #[getter]
229  fn sys_id   (&self) -> u8 { 
230    self.header.sys_id
231  }
232
233  #[getter]
234  fn packet_id(&self) -> u8  {
235    self.header.packet_id
236  }
237
238  #[getter]
239  fn length   (&self) -> u16 {
240    self.header.length
241  }
242
243  #[getter]
244  fn daq_count(&self) -> u16 {
245    self.header.daq_count
246  }
247
248  #[getter]
249  fn sys_time (&self) -> u64 {
250    self.header.sys_time
251  }
252
253  #[getter]
254  fn version  (&self) -> u8  {
255    self.header.version
256  }
257
258  fn __repr__(&self) -> PyResult<String> {
259    Ok(format!("<PyO3Wrapper: {}>", self.header))
260  }
261
262}
263
264#[pyclass]
265#[pyo3(name="TrackerPacket")]
266pub struct PyTrackerPacket {
267  packet : tel_api::TrackerPacket,
268}
269
270impl PyTrackerPacket {
271  pub fn set_packet(&mut self, packet : tel_api::TrackerPacket) {
272    self.packet = packet;
273  }
274}
275
276#[pymethods]
277impl PyTrackerPacket {
278  #[new]
279  fn new() -> Self {
280    Self {
281      packet : tel_api::TrackerPacket::new(),
282    }
283  }
284
285  #[getter]
286  fn header(&self) -> PyTrackerHeader {
287    let mut pth = PyTrackerHeader::new();
288    pth.set_header(self.packet.tracker_header.clone());
289    pth
290  }
291
292  #[getter]
293  fn events(&self) -> Vec<PyTrackerEvent> {
294    let mut events = Vec::<PyTrackerEvent>::new();
295    for k in &self.packet.events {
296      let mut pyev = PyTrackerEvent::new();
297      pyev.set_event(k.clone());
298      events.push(pyev);
299    }
300    events
301  }
302
303  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
304    match tel_api::TrackerPacket::from_bytestream(&packet.packet.payload, &mut 0) {
305      Ok(tpacket) => {
306        self.set_packet(tpacket);
307        self.packet.telemetry_header = packet.packet.header.clone();
308      }
309      Err(err) => {
310        return Err(PyValueError::new_err(err.to_string()));
311      }  
312    }
313    Ok(())
314  }
315  
316  fn __repr__(&self) -> PyResult<String> {
317    Ok(format!("<PyO3Wrapper: {}>", self.packet))
318  }
319}
320
321#[derive(Clone)]
322#[pyclass]
323#[pyo3(name="TelemetryPacket")]
324pub struct PyTelemetryPacket {
325  pub packet : tel_api::TelemetryPacket,
326}
327
328
329impl PyTelemetryPacket {
330  pub fn set_packet(&mut self, packet : tel_api::TelemetryPacket) {
331    self.packet = packet;
332  }
333}
334
335#[pymethods]
336impl PyTelemetryPacket {
337  #[new]
338  pub fn new() -> Self {
339    Self {
340      packet : tel_api::TelemetryPacket::new(),
341    }
342  }
343  
344  #[getter]
345  fn header(&self) -> PyTelemetryHeader {
346    let mut header = PyTelemetryHeader::new();
347    header.set_header(self.packet.header.clone());
348    header
349  }
350  
351  #[getter]
352  fn payload(&self) -> Vec<u8> {
353    // FIXME
354    self.packet.payload.clone()
355  }
356
357  #[getter]
358  fn packet_type(&self) -> tel_api::TelemetryPacketType {
359    let ptype = tel_api::TelemetryPacketType::from(self.packet.header.ptype);
360    ptype
361  }
362
363  fn __repr__(&self) -> PyResult<String> {
364    Ok(format!("<PyO3Wrapper: {}>", self.packet))
365  }
366}
367
368
369/// Read the GAPS binary data stream, dubbed as "telemetry"
370///
371/// These are binary files, typically with a name like RAW240716_094940.bin,
372/// where the numbers are the UTC timestamp when the file has been written.
373///
374/// These telemetry files contains data seperated by delimiters, called "packets".
375/// The TelemetryPacketReader will recognized the delimiters, and emit these 
376/// individual packets.
377///  
378/// When creating a new instalnce of TelemetryPacketReader, the intance will emit packets
379/// until the whole file is consumed. To re-use the same instance, call
380/// TelemetryPacketReader::rewind
381///
382/// # Arguments
383///
384/// * filename - the name of the binary file to be read
385/// * filter   - emit only TelemetryPackets of a certain type. If set to 
386///              TelemetryPacketType::Unknown, all packets will be emitted
387/// * start    - [NOT IMPLEMENTED]
388/// * stop     - [NOT IMPLEMENTED]
389#[pyclass]
390#[pyo3(name="TelemetryPacketReader")]
391pub struct PyTelemetryPacketReader {
392  reader   : tel_io_api::TelemetryPacketReader,
393  //filelist : Vec<String>,
394}
395
396#[pymethods]
397impl PyTelemetryPacketReader {
398  #[new]
399  #[pyo3(signature = (filename, filter=tel_api::TelemetryPacketType::Unknown))]
400  fn new(filename : String, filter : tel_api::TelemetryPacketType) -> Self {
401    //#[pyo3(signature = (filename, filter=tel_api::TelemetryPacketType::Unknown,start=0, nevents=0))]
402    // FIXME add start and nevents  
403    //, start : usize, nevents : usize) -> Self {
404    //if filenames.len() == 0 {
405    //  panic!("Filenames list arguments needs to have at least a single file!");
406    //}
407    //let first_filename = filenames[0];
408    //let new_fnames = Vec::<String>::new();
409    //let new_fnames = filenames[1..].to_vec();
410    let mut reader_init = Self {
411      reader     : tel_io_api::TelemetryPacketReader::new(filename),
412      //filelist   : filenames
413    };
414    reader_init.reader.filter = filter;
415    reader_init
416  }
417
418  /// Any filter will be selecting packets of only this type
419  ///
420  /// If all packets should be allowed, set the packet type to Unknown
421  #[getter]
422  fn get_filter(&self) -> PyResult<tel_api::TelemetryPacketType> {
423    Ok(self.reader.filter)
424  }
425
426  #[setter]
427  fn set_filter(&mut self, ptype : tel_api::TelemetryPacketType) -> PyResult<()> {
428    self.reader.filter = ptype;
429    Ok(())
430  }
431
432  #[getter]
433  fn get_filenames(&self) -> Vec<String> {
434    self.reader.filenames.clone()
435  }
436
437  #[getter]
438  fn get_current_file(&self) -> String {
439    if self.reader.file_index >= self.reader.filenames.len() {
440      return String::from("");
441    }
442    self.reader.filenames[self.reader.file_index].clone()
443  }
444  /// Return an inventory of packets in this file, where TelemetryPacketType is
445  /// represented by its associtated integer
446  ///
447  /// # Arguments
448  /// * verbose    : print the associated TelemetryPacketTypes (names)
449  #[pyo3(signature = (verbose=false))]
450  fn get_packet_index(&mut self, verbose : bool) -> PyResult<HashMap<u8, usize>> {
451    let idx = self.reader.get_packet_index()?;
452    if verbose {
453      println!("<TelemetryPacketReader::index");
454      for k in idx.keys() {
455        let ptype = tel_api::TelemetryPacketType::from(*k);
456        println!("--> {} ({}) : {}",k, ptype, idx.get(&k).unwrap());
457      }
458      println!(">");
459    }
460    self.reader.rewind()?;
461    Ok(idx)
462  }
463
464  /// "Rewind" the file, meaning set the cursor to the beginning again.
465  ///
466  /// All packets can be emitted again
467  fn rewind(&mut self) -> PyResult<()> {
468    Ok(self.reader.rewind()?)
469  }
470
471  fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<PyTelemetryPacket> {
472    match slf.reader.next() { 
473      Some(tp) => {
474        let mut pytp = PyTelemetryPacket::new();
475        pytp.set_packet(tp);
476        return Some(pytp)
477      }
478      None => {
479        return None;
480      }
481    }
482    //
483  }
484
485  fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
486    slf 
487  }
488
489  fn __repr__(&self) -> PyResult<String> {
490    Ok(format!("<PyO3Wrapper: {}>", self.reader))
491  }
492}
493
494
495// FIXME - with the new style tracker hit, we might not 
496// need the gaps event anymore
497//#[pyfunction]
498//fn get_gapsevents(fname : String) -> Vec<PyGapsEvent> {
499//  let mut pyevents = Vec::<PyGapsEvent>::new();
500//  let events = tel_io_api::get_gaps_events(fname);
501//  for ev in events {
502//    let mut pyev = PyGapsEvent::new();
503//    pyev.set_tof(ev.tof.clone());
504//    pyev.set_tracker(ev.tracker.clone());
505//    pyevents.push(pyev);
506//  }
507//  pyevents
508//}
509
510
511#[pyclass]
512#[pyo3(name="GapsTelemetryEvent")]
513pub struct PyGapsEvent {
514  event   : tel_api::GapsEvent,
515}
516
517impl PyGapsEvent {
518  pub fn set_tof(&mut self, tes : tof_api::TofEventSummary) {
519    self.event.tof = tes;
520  }
521  
522  pub fn set_tracker(&mut self, trk : Vec<tel_api::TrackerEvent>) {
523    self.event.tracker = trk;
524  }
525}
526
527#[pymethods]
528impl PyGapsEvent {
529  #[new]
530  fn new() -> Self {
531    Self {
532      event     : tel_api::GapsEvent::new(),
533    }
534  }
535
536  #[getter]
537  fn tof(&self) -> PyTofEventSummary {
538    let mut tof =  PyTofEventSummary::new();
539    tof.event = self.event.tof.clone();
540    tof
541  }
542
543  #[getter]
544  fn tracker(&self) -> Vec<PyTrackerEvent> {
545    let mut trk_ev = Vec::<PyTrackerEvent>::new();
546    for ev in &self.event.tracker {
547      let mut py_ev = PyTrackerEvent::new();
548      py_ev.set_event(ev.clone());
549      trk_ev.push(py_ev)
550    }
551    trk_ev
552  }
553  
554  fn __repr__(&self) -> PyResult<String> {
555    Ok(format!("<PyO3Wrapper: {}>", self.event))
556  }
557}
558
559
560/// Representation of a TrackerHit 
561///
562/// This is the same representation as in the GSE DB
563#[pyclass]
564#[pyo3(name="TrackerHit")]
565#[derive(Debug, Clone)]
566pub struct PyTrackerHit {
567  //th : tel_api::TrackerHit,
568  pub row             : u8,
569  pub module          : u8,
570  pub channel         : u8,
571  pub adc             : u16,
572  pub asic_event_code : u8,
573}
574
575impl PyTrackerHit {
576  pub fn set_hit(&mut self, th : tel_api::TrackerHit) {
577    self.row             = th.row;
578    self.module          = th.module;
579    self.channel         = th.channel;
580    self.adc             = th.adc;
581    self.asic_event_code = th.asic_event_code;
582  }
583}
584
585#[pymethods]
586impl PyTrackerHit {
587
588  #[new]
589  fn new() -> Self {
590    Self {
591      row             : 0,
592      module          : 0,
593      channel         : 0,
594      adc             : 0,
595      asic_event_code : 0,
596    }
597  }
598
599  #[getter]
600  fn row(&self) -> u8 {
601    self.row
602  }
603
604  #[getter]
605  fn module(&self) -> u8 {
606    self.module
607  }
608
609  #[getter]
610  fn channel(&self) -> u8 {
611    self.channel
612  }
613
614  #[getter]
615  fn adc(&self) -> u16 {
616    self.adc
617  }
618
619  /// Change the ADC value, e.g. if the 
620  /// pedestal should be subtracted
621  fn subtract_pedestal(&mut self, pedestal : u16) {
622    self.adc -= pedestal;
623  }
624
625  #[getter]
626  fn asic_event_code(&self) -> u8 {
627    self.asic_event_code
628  }
629
630  fn __repr__(&self) -> PyResult<String> {
631    Ok(format!("{}", self))
632  }
633}
634
635impl fmt::Display for PyTrackerHit {
636  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
637    let mut repr = String::from("<PyTrackerHit:");
638    repr += &(format!("\n  Row           : {}" ,self.row));
639    repr += &(format!("\n  Module        : {}" ,self.module));
640    repr += &(format!("\n  Channel       : {}" ,self.channel));
641    repr += &(format!("\n  ADC           : {}" ,self.adc));
642    repr += &(format!("\n  ASIC Ev. Code : {}>",self.asic_event_code));
643    write!(f, "{}", repr)
644  }
645}
646
647////////////////////////////////////////////////////////////
648
649/// Updated representation of a TrackerHit 
650///
651/// A new-style tracker hit, which is not part 
652/// of a TrackerEvent anymore and can stand by 
653/// itself
654///
655/// Note that the values are u16, this is in 
656/// accordance with what is in bfsw
657#[pyclass]
658#[pyo3(name="TrackerHitV2")]
659#[derive(Debug, Clone)]
660pub struct PyTrackerHitV2 {
661  pub layer           : u16,
662  pub row             : u16,
663  pub module          : u16,
664  pub channel         : u16,
665  pub adc             : u16,
666  pub oscillator      : u64,
667  pub energy          : f64,
668}
669
670impl PyTrackerHitV2 {
671  pub fn set_hit(&mut self, th : tel_api::TrackerHitV2) {
672    self.layer           = th.layer;
673    self.row             = th.row;
674    self.module          = th.module;
675    self.channel         = th.channel;
676    self.adc             = th.adc;
677    self.oscillator      = th.oscillator;
678  }
679}
680
681#[pymethods]
682impl PyTrackerHitV2 {
683
684  #[new]
685  fn new() -> Self {
686    Self {
687      layer           : 0,
688      row             : 0,
689      module          : 0,
690      channel         : 0,
691      adc             : 0,
692      oscillator      : 0,
693      energy          : 0.0,
694    }
695  }
696  
697  /// Set the energy field with the given energy, 
698  /// as calculated from a transfer function
699  fn set_energy(&mut self, energy : f64) {
700    self.energy = energy;
701  }
702
703  /// Change the ADC value, e.g. if the 
704  /// pedestal should be subtracted
705  fn subtract_pedestal(&mut self, pedestal : u16) {
706    self.adc -= pedestal;
707  }
708
709  #[getter]
710  pub fn get_stripid(&self) -> u32 {
711    self.channel as u32 + (self.module as u32)*100 + (self.row as u32)*10000 + (self.layer as u32)*100000
712  }
713
714  #[getter]
715  fn layer(&self) -> u16 {
716    self.layer
717  }
718
719  #[getter]
720  fn row(&self) -> u16 {
721    self.row
722  }
723
724  #[getter]
725  fn module(&self) -> u16 {
726    self.module
727  }
728
729  #[getter]
730  fn channel(&self) -> u16 {
731    self.channel
732  }
733
734  #[getter]
735  fn adc(&self) -> u16 {
736    self.adc
737  }
738
739  #[getter]
740  fn oscillator(&self) -> u64 {
741    self.oscillator
742  }
743  
744  fn __repr__(&self) -> PyResult<String> {
745    Ok(format!("{}", self))
746  }
747}
748
749impl fmt::Display for PyTrackerHitV2 {
750  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
751    let mut repr = String::from("<PyTrackerHitV2:");
752    repr += &(format!("\n  Layer, Row, Module, Channel : {} {} {} {}" ,self.layer, self.row, self.module, self.channel));
753    repr += &(format!("\n  ADC           : {}" ,self.adc));
754    repr += &(format!("\n  Oscillator    : {}" ,self.oscillator));
755    repr += &(format!("\n  Calib energy  : {}>",self.energy));
756    write!(f, "{}", repr)
757  }
758}
759
760
761
762//// Implement the AsRef<PyAny> trait
763//impl AsRef<PyAny> for PyTrackerHit {
764//  fn as_ref(&self) -> &PyAny {
765//    Python::with_gil(|py| {
766//      let py_object = PyCell::new(py, self).unwrap();
767//      py_object.as_ref(py)
768//    })
769//  }
770//}
771
772#[pyclass]
773#[pyo3(name="Trackerevent")]
774pub struct PyTrackerEvent {
775  te : tel_api::TrackerEvent
776}
777
778impl PyTrackerEvent {
779  fn set_event(&mut self, te : tel_api::TrackerEvent) {
780    self.te = te;
781  }
782}
783
784#[pymethods]
785impl PyTrackerEvent {
786  #[new]
787  fn new() -> Self {
788    Self {
789      te : tel_api::TrackerEvent::new(),
790    }
791  } 
792
793  /// Loop over the filtered hits, returning only those satisfying a condition
794  ///
795  /// # Arguments:
796  /// 
797  /// * filter : filter function - take input hit and decide if it should be 
798  ///            returned.
799  ///            E.g, this can be something like 
800  ///            .filter_hits(lambda h : h.asic_event_code == 0 or h.asic_event_code ==2)
801  pub fn filter_hits(&self, filter : &Bound<'_,PyFunction>) -> PyResult<Vec<PyTrackerHit>> {
802    let mut filtered_hits = Vec::<PyTrackerHit>::new();
803    for h in self.hits() {
804      //let hit_ref = h.as_ref(py);
805      let result : bool = filter.call1((h.clone(),))?.extract()?;
806      if result {
807        filtered_hits.push(h);
808      }
809    }
810    Ok(filtered_hits)
811  }
812
813  #[getter]
814  fn layer(&self) -> u8 {
815    self.te.layer
816  }
817  
818  #[getter]
819  fn flags1(&self) -> u8 {
820    self.te.flags1
821  }
822  
823  #[getter]
824  fn event_id(&self) -> u32 {
825    self.te.event_id
826  }
827  
828  #[getter]
829  fn event_time(&self) -> u64 {
830    self.te.event_time
831  }
832
833  //fn from_trackerpacket(&self, TrackerPacket) -> PyResult<()> {
834  //  match tel_api::TrackerEvent::from_bytestream(&packet.packet.payload, &mut 0) {
835  //    Ok(event) => {
836  //      self.set_event(event);
837  //      self.event.header = packet.packet.header.clone();
838  //    }
839  //    Err(err) => {
840  //      return Err(PyValueError::new_err(err.to_string()));
841  //    }  
842  //  }
843  //  Ok(()) 
844  //}
845
846  #[getter]
847  fn hits(&self) -> Vec<PyTrackerHit> {
848    let mut hits = Vec::<PyTrackerHit>::new();
849    for h in &self.te.hits {
850      let mut py_hit = PyTrackerHit::new();
851      py_hit.set_hit(*h);
852      hits.push(py_hit);
853    }
854    hits
855  }
856
857  fn __repr__(&self) -> PyResult<String> {
858    Ok(format!("<PyO3Wrapper: {}>", self.te))
859  }
860}
861
862#[pyclass]
863#[pyo3(name="MagnetoMeterPacket")]
864pub struct PyMagnetoMeterPacket {
865  mag : tel_api::MagnetoMeter,
866}
867
868#[pymethods]
869impl PyMagnetoMeterPacket {
870
871  #[new]
872  fn new() -> Self {
873    Self {
874      mag : tel_api::MagnetoMeter::new(),
875    }
876  }
877
878 #[getter]
879 fn temp         (&self) -> u16 { 
880   self.mag.temp
881 }
882 
883 #[getter]
884 fn mag_x        (&self) -> u16 { 
885   self.mag.mag_x
886 }
887 
888 #[getter]
889 fn mag_y        (&self) -> u16 { 
890   self.mag.mag_y
891 }
892 
893 #[getter]
894 fn mag_z        (&self) -> u16 { 
895   self.mag.mag_z
896 }
897 
898 //#[getter]
899 //fn mag_tot        (&self) -> u16 { 
900 //  self.mag.mag_z
901 //}
902 
903 #[getter]
904 fn acc_x        (&self) -> u16 { 
905   self.mag.acc_x
906 }
907 
908 #[getter]
909 fn acc_y        (&self) -> u16 { 
910   self.mag.acc_y
911 }
912 
913 #[getter]
914 fn acc_z        (&self) -> u16 { 
915   self.mag.acc_z
916 }
917 
918 #[getter]
919 fn roll         (&self) -> u16 { 
920   self.mag.roll
921 }
922 
923 #[getter]
924 fn pitch        (&self) -> u16 { 
925   self.mag.pitch
926 }
927 
928 #[getter]
929 fn yaw          (&self) -> u16 { 
930   self.mag.yaw
931 }
932 
933 #[getter]
934 fn mag_roll     (&self) -> u16 { 
935   self.mag.mag_roll
936 }
937 
938 #[getter]
939 fn mag_field    (&self) -> u16 { 
940   self.mag.mag_field
941 }
942 
943 #[getter]
944 fn grav_field   (&self) -> u16 { 
945   self.mag.grav_field
946 }
947 
948 //fn expected_size(&self) -> u64 { 
949 //fn end_byte     (&self) -> u16 { 
950 //fn zero         (&self) -> u8  { 
951 //fn ndata        (&self) -> u8  { 
952
953}
954
955#[pyclass]
956#[pyo3(name="GPSPacket")]
957pub struct PyGPSPacket {
958  gps : tel_api::GPSPacket,
959}
960
961impl PyGPSPacket {
962  pub fn set_gps(&mut self, gps : tel_api::GPSPacket) {
963    self.gps = gps;
964  }
965}
966
967#[pymethods]
968impl PyGPSPacket {
969
970  #[new]
971  fn new() -> Self {
972    Self {
973      gps : tel_api::GPSPacket::new(),
974    }
975  }
976
977  #[getter]
978  fn utctime(&self) -> u32 {
979    self.gps.utc_time
980  }
981  
982  #[getter]
983  fn gps_info(&self) -> u8 {
984    self.gps.gps_info
985  }
986
987  /// Populate a GPSPacket from a TelemetryPacket.
988  ///
989  /// Telemetry packet type should be 82 (MergedEvent)
990  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
991    match tel_api::GPSPacket::from_bytestream(&packet.packet.payload, &mut 0) {
992      Ok(gps) => {
993        self.set_gps(gps);
994        self.gps.telemetry_header = packet.packet.header.clone();
995      }
996      Err(err) => {
997        return Err(PyValueError::new_err(err.to_string()));
998      }  
999    }
1000    Ok(())
1001  }
1002
1003  fn __repr__(&self) -> PyResult<String> {
1004    Ok(format!("<PyO3Wrapper: {}>", self.gps))
1005  }
1006}
1007
1008#[pyclass]
1009#[pyo3(name="TrackerTempLeakPacket")]
1010pub struct PyTrackerTempLeakPacket {
1011  tl : tel_api::TrackerTempLeakPacket,
1012}
1013
1014impl PyTrackerTempLeakPacket {
1015  pub fn set_tl(&mut self, tl : tel_api::TrackerTempLeakPacket) {
1016    self.tl = tl;
1017  }
1018}
1019
1020#[pymethods]
1021impl PyTrackerTempLeakPacket {
1022
1023  #[new]
1024  fn new() -> Self {
1025    Self {
1026      tl : tel_api::TrackerTempLeakPacket::new(),
1027    }
1028  }
1029
1030  #[getter]
1031  fn row_offset(&self) -> u8 {
1032    self.tl.row_offset
1033  }
1034  
1035  #[getter]
1036  fn temp_leak(&self) -> [[u32;6];6] {
1037    self.tl.templeak
1038  }
1039  
1040  #[getter]
1041  fn seu(&self) -> [[u32;6];6] {
1042    self.tl.seu
1043  }
1044
1045  /// Populate a TrackerTempLeakPacket from a TelemetryPacket.
1046  ///
1047  /// Telemetry packet type should be 82 (MergedEvent)
1048  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
1049    match tel_api::TrackerTempLeakPacket::from_bytestream(&packet.packet.payload, &mut 0) {
1050      Ok(tl) => {
1051        self.set_tl(tl);
1052        self.tl.telemetry_header = packet.packet.header.clone();
1053      }
1054      Err(err) => {
1055        return Err(PyValueError::new_err(err.to_string()));
1056      }  
1057    }
1058    Ok(())
1059  }
1060
1061  fn __repr__(&self) -> PyResult<String> {
1062    Ok(format!("<PyO3Wrapper: {}>", self.tl))
1063  }
1064}
1065
1066#[pyclass]
1067#[pyo3(name="TrackerDAQTempPacket")]
1068pub struct PyTrackerDAQTempPacket {
1069  tp : tel_api::TrackerDAQTempPacket,
1070}
1071
1072impl PyTrackerDAQTempPacket {
1073  pub fn set_tp(&mut self, tp : tel_api::TrackerDAQTempPacket) {
1074    self.tp = tp;
1075  }
1076}
1077
1078#[pymethods]
1079impl PyTrackerDAQTempPacket {
1080
1081  #[new]
1082  fn new() -> Self {
1083    Self {
1084      tp : tel_api::TrackerDAQTempPacket::new(),
1085    }
1086  }
1087
1088  #[getter]
1089  fn rom_id(&self) -> [u64;256] {
1090    self.tp.rom_id
1091  }
1092  
1093  #[getter]
1094  fn temp(&self) -> [u16;256] {
1095    self.tp.temp
1096  }
1097  
1098  /// Populate a TrackerTempLeakPacket from a TelemetryPacket.
1099  ///
1100  /// Telemetry packet type should be 82 (MergedEvent)
1101  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
1102    let ptype = tel_api::TelemetryPacketType::from(packet.packet.header.ptype);
1103    if ptype != tel_api::TelemetryPacketType::AnyTrackerHK {
1104      return Err(PyValueError::new_err(format!("This is packet has type {}, but it should have {}", ptype, tel_api::TelemetryPacketType::AnyTrackerHK)));
1105    }
1106    if packet.packet.payload.len() <= 18 {
1107      return Err(PyValueError::new_err("StreamTooShort"));
1108    }
1109    match tel_api::TrackerDAQTempPacket::from_bytestream(&packet.packet.payload, &mut 0) {
1110      Ok(tp) => {
1111        self.set_tp(tp);
1112        self.tp.telemetry_header = packet.packet.header.clone();
1113      }
1114      Err(err) => {
1115        return Err(PyValueError::new_err(err.to_string()));
1116      }  
1117    }
1118    Ok(())
1119  }
1120
1121  fn __repr__(&self) -> PyResult<String> {
1122    Ok(format!("<PyO3Wrapper: {}>", self.tp))
1123  }
1124}
1125
1126#[pyclass]
1127#[pyo3(name="TrackerDAQHSKPacket")]
1128pub struct PyTrackerDAQHSKPacket {
1129  tp : tel_api::TrackerDAQHSKPacket,
1130}
1131
1132impl PyTrackerDAQHSKPacket {
1133  pub fn set_tp(&mut self, tp : tel_api::TrackerDAQHSKPacket) {
1134    self.tp = tp;
1135  }
1136}
1137
1138#[pymethods]
1139impl PyTrackerDAQHSKPacket {
1140
1141  #[new]
1142  fn new() -> Self {
1143    Self {
1144      tp : tel_api::TrackerDAQHSKPacket::new(),
1145    }
1146  }
1147
1148  #[getter]
1149  fn temp(&self) -> [u16;12] {
1150    self.tp.temp
1151  }
1152  
1153  /// Populate a TrackerTempLeakPacket from a TelemetryPacket.
1154  ///
1155  /// Telemetry packet type should be 82 (MergedEvent)
1156  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
1157    let ptype = tel_api::TelemetryPacketType::from(packet.packet.header.ptype);
1158    if ptype != tel_api::TelemetryPacketType::AnyTrackerHK {
1159      return Err(PyValueError::new_err(format!("This is packet has type {}, but it should have {}", ptype, tel_api::TelemetryPacketType::AnyTrackerHK)));
1160    }
1161    if packet.packet.payload.len() <= 18 {
1162      return Err(PyValueError::new_err("StreamTooShort"));
1163    }
1164    match tel_api::TrackerDAQHSKPacket::from_bytestream(&packet.packet.payload, &mut 0) {
1165      Ok(tp) => {
1166        self.set_tp(tp);
1167        self.tp.telemetry_header = packet.packet.header.clone();
1168      }
1169      Err(err) => {
1170        return Err(PyValueError::new_err(err.to_string()));
1171      }  
1172    }
1173    Ok(())
1174  }
1175
1176  fn __repr__(&self) -> PyResult<String> {
1177    Ok(format!("<PyO3Wrapper: {}>", self.tp))
1178  }
1179}
1180
1181#[pyclass]
1182#[pyo3(name="TrackerEventIDEchoPacket")]
1183pub struct PyTrackerEventIDEchoPacket {
1184  tp : tel_api::TrackerEventIDEchoPacket,
1185}
1186
1187impl PyTrackerEventIDEchoPacket {
1188  pub fn set_tp(&mut self, tp : tel_api::TrackerEventIDEchoPacket) {
1189    self.tp = tp;
1190  }
1191}
1192
1193#[pymethods]
1194impl PyTrackerEventIDEchoPacket {
1195
1196  #[new]
1197  fn new() -> Self {
1198    Self {
1199      tp : tel_api::TrackerEventIDEchoPacket::new(),
1200    }
1201  }
1202
1203  #[getter]
1204  fn temp(&self) -> [u16;12] {
1205    self.tp.temp
1206  }
1207  
1208  /// Populate a TrackerEventIDEchoPacket from a TelemetryPacket.
1209  ///
1210  /// Telemetry packet type should be 82 (MergedEvent)
1211  fn from_telemetrypacket(&mut self, packet : PyTelemetryPacket) -> PyResult<()> {
1212    let ptype = tel_api::TelemetryPacketType::from(packet.packet.header.ptype);
1213    if ptype != tel_api::TelemetryPacketType::AnyTrackerHK {
1214      return Err(PyValueError::new_err(format!("This is packet has type {}, but it should have {}", ptype, tel_api::TelemetryPacketType::AnyTrackerHK)));
1215    }
1216    if packet.packet.payload.len() <= 18 {
1217      return Err(PyValueError::new_err("StreamTooShort"));
1218    }
1219    match tel_api::TrackerEventIDEchoPacket::from_bytestream(&packet.packet.payload, &mut 0) {
1220      Ok(tp) => {
1221        self.set_tp(tp);
1222        self.tp.telemetry_header = packet.packet.header.clone();
1223      }
1224      Err(err) => {
1225        return Err(PyValueError::new_err(err.to_string()));
1226      }  
1227    }
1228    Ok(())
1229  }
1230
1231  fn __repr__(&self) -> PyResult<String> {
1232    Ok(format!("<PyO3Wrapper: {}>", self.tp))
1233  }
1234}
1235
1236