1use crate::prelude::*;
7
8#[cfg_attr(feature="pybindings", pyclass)]
9pub struct TelemetryEvent {
10 pub header : TelemetryPacketHeader,
11 pub creation_time : u64,
12 pub event_id : u32,
13 pub tracker_hits : Vec<TrackerHit>,
14 pub tracker_oscillators : Vec<u64>,
15 pub tof_event : TofEvent,
16 pub raw_data : Vec<u8>,
17 pub flags0 : u8,
18 pub flags1 : u8,
19 pub version : u8
20}
21
22impl TelemetryEvent {
23
24 pub fn new() -> Self {
25 let mut tracker_oscillators = Vec::<u64>::new();
26 for _ in 0..10 {
27 tracker_oscillators.push(0);
28 }
29 Self {
30 header : TelemetryPacketHeader::new(),
31 creation_time : 0,
32 event_id : 0,
33 tracker_hits : Vec::<TrackerHit>::new(),
34 tracker_oscillators : tracker_oscillators,
35 tof_event : TofEvent::new(),
36 raw_data : Vec::<u8>::new(),
37 flags0 : 0,
38 flags1 : 1,
39 version : 0,
40 }
41 }
42
43 #[cfg(feature="database")]
45 pub fn dehydrate(&mut self, tof_paddles : &HashMap<u8,TofPaddle>, trk_strips : &HashMap<u32, TrackerStrip>) {
46 self.tof_event.set_paddles(tof_paddles);
47 for h in &mut self.tracker_hits {
48 h.set_coordinates(trk_strips);
49 }
50 }
51
52 #[cfg(feature="database")]
53 pub fn mask_strips(&mut self, masks : &HashMap<u32, TrackerStripMask>) {
54 let mut clean_hits = Vec::<TrackerHit>::with_capacity(self.tracker_hits.len());
55 for h in &self.tracker_hits {
56 if !masks.contains_key(&h.get_stripid()) {
57 warn!("We don't have a mask information for strip id {}", h.get_stripid());
58 continue;
59 }
60 if masks[&h.get_stripid()].active {
61 clean_hits.push(h.clone());
62 }
63 }
64 self.tracker_hits = clean_hits;
65 }
66
67
68 #[cfg(feature="database")]
70 pub fn apply_signal_cut(&mut self, cut : f32, pedestals : &HashMap<u32, TrackerStripPedestal>) {
71 let mut clean_hits = Vec::<TrackerHit>::with_capacity(self.tracker_hits.len());
72 for h in &self.tracker_hits {
73 if !pedestals.contains_key(&h.get_stripid()) {
74 warn!("We don't have pedestal information for strip id {}", h.get_stripid());
75 continue;
76 }
77 let ped = &pedestals[&h.get_stripid()];
78 if (h.adc as f32) - ped.pedestal_mean > (cut * ped.pedestal_sigma){
79 clean_hits.push(h.clone());
80 }
81 }
82 self.tracker_hits = clean_hits;
83 }
84
85 #[cfg(feature="database")]
87 pub fn cmn_noise(hit : &TrackerHit,
88 pedestals : &HashMap<u32, TrackerStripPedestal>,
89 cmn_noise : &HashMap<u32, TrackerStripCmnNoise>) -> Option<f32> {
90 let stripid = hit.get_stripid();
91 if !cmn_noise.contains_key(&stripid) {
92 warn!("We don't have pedestal information for strip id {}", stripid);
93 return None;
94 }
95 if !pedestals.contains_key(&stripid) {
96 warn!("We don't have pedestal information for strip id {}", stripid);
97 return None;
98 }
99 let mut cmn_level = 0.0f32;
100 let adc_ped_sub = hit.adc as f32 - pedestals[&stripid].pedestal_mean;
101 if adc_ped_sub < 400.0 {
102 cmn_level = cmn_noise[&stripid].common_level(hit.adc as f32);
103 }
104 return Some(adc_ped_sub - cmn_noise[&stripid].gain * cmn_level);
105 }
106
107 #[cfg(feature="database")]
109 pub fn get_trk_energy(adc : f32, tf : &TrackerStripTransferFunction) -> f32 {
110 let mut energy = 0.0f32;
111 let mut adc_m = adc;
112 if adc_m <= 0.0 {
113 return energy;
114 }
115 if adc_m > 1600.0 {
116 adc_m = 1600.0;
117 }
118 #[allow(non_snake_case)]
119 let mV2keV = 0.841f32;
120 let voltage = tf.transfer_fn(adc_m);
123 println!("voltage {}", voltage);
124 energy = voltage*mV2keV;
125 energy /= 1000.0;
126 println!("adc : {} , energy {}", adc_m, energy);
127 return energy;
128 }
129
130 #[cfg(feature="database")]
131 pub fn calibrate_tracker(&mut self,
132 remove_cmn_noise : bool,
133 pedestals : &HashMap<u32, TrackerStripPedestal>,
134 transfer_fn : &HashMap<u32, TrackerStripTransferFunction>,
135 cmn_noise : &HashMap<u32, TrackerStripCmnNoise>) {
136 for h in &mut self.tracker_hits {
138 let stripid = h.get_stripid();
139 if !pedestals.contains_key(&stripid) {
141 warn!("Pedestal map does not contain strip {}. Will not calculate energy!", stripid);
142 continue;
143 }
144 if !transfer_fn.contains_key(&stripid) {
145 warn!("Transfer fn for strip {} not available. Will not calculate energy!", stripid);
146 continue;
147 }
148 let adc_no_ped = h.adc as f32 - pedestals[&stripid].pedestal_mean;
149 if remove_cmn_noise {
151 match Self::cmn_noise(&h, pedestals, cmn_noise) {
152 None => {
153 h.energy = Self::get_trk_energy(adc_no_ped, &transfer_fn[&stripid]);
154 }
155 Some(cmn) => {
156 h.energy = Self::get_trk_energy(cmn, &transfer_fn[&stripid]);
157 }
158 }
159 } else {
160 h.energy = Self::get_trk_energy(adc_no_ped, &transfer_fn[&stripid]);
161 }
162 }
163 }
164}
165
166
167impl TelemetryPackable for TelemetryEvent {
168 }
171
172impl Serialization for TelemetryEvent {
173
174 fn from_bytestream(stream : &Vec<u8>,
175 pos : &mut usize)
176 -> Result<Self, SerializationError> {
177 let mut me = Self::new();
178 let version = parse_u8(stream, pos);
179 me.version = version;
180 me.flags0 = parse_u8(stream, pos);
182 if version == 0 {
185 me.flags1 = parse_u8(stream, pos);
186 } else {
187 *pos += 8;
188 }
189
190 me.event_id = parse_u32(stream, pos);
191 let _tof_delim = parse_u8(stream, pos);
193 if stream.len() <= *pos + 2 {
195 error!("Not able to parse merged event!");
196 return Err(SerializationError::StreamTooShort);
197 }
198 let num_tof_bytes = parse_u16(stream, pos) as usize;
199 if stream.len() < *pos+num_tof_bytes {
201 error!("Not enough bytes for TOF packet! Expected {}, seen {}", *pos+num_tof_bytes as usize, stream.len());
202 return Err(SerializationError::StreamTooShort);
203 }
204 let pos_before = *pos;
205 if num_tof_bytes != 0 {
206 let tof_pack = TofPacket::from_bytestream(stream, pos)?;
207 let ts = tof_pack.unpack::<TofEvent>()?;
208 me.tof_event = ts;
210 }
211 if pos_before + num_tof_bytes != *pos {
212 error!("Byte misalignment. Expected {num_tof_bytes}, got {pos} - {pos_before}");
213 return Err(SerializationError::WrongByteSize);
214 }
215 let trk_delim = parse_u8(stream, pos);
216
217 if trk_delim != 0xbb {
219 return Err(SerializationError::HeadInvalid);
220 }
221 if version == 1 {
222 let num_trk_hits = parse_u16(stream, pos);
223 if (*pos + (num_trk_hits as usize)*4 ) > stream.len() {
224 return Err(SerializationError::StreamTooShort);
225 }
226 for _ in 0..num_trk_hits {
227 let mut hit = TrackerHit::new();
228 let strip_id = parse_u16(stream, pos);
229 let adc = parse_u16(stream, pos);
230 hit.channel = strip_id & 0b11111;
231 hit.module = (strip_id >> 5) & 0b111;
232 hit.row = (strip_id >> 8) & 0b111;
233 hit.layer = (strip_id >> 11) & 0b1111;
234 hit.adc = adc;
235 me.tracker_hits.push(hit);
236 }
237 let oscillators_delimiter = parse_u8(stream, pos);
239 if oscillators_delimiter != 0xcc {
240 return Err(SerializationError::HeadInvalid);
241 }
242 let osc_flags = parse_u8(stream, pos);
243 let mut oscillator_idx = Vec::<u8>::new();
244 for j in 0..8 {
245 if (osc_flags >> j & 0b1) > 0 {
246 oscillator_idx.push(j)
247 }
248 }
249 if (*pos + oscillator_idx.len()*6) > stream.len() {
250 return Err(SerializationError::StreamTooShort);
251 }
252 for idx in oscillator_idx.iter() {
253 let lower = parse_u32(stream, pos);
254 let upper = parse_u16(stream, pos);
255 let osc : u64 = (upper as u64) << 32 | (lower as u64);
256 me.tracker_oscillators[*idx as usize] = osc;
257 }
258 } else if version == 0 {
259 error!("Unsupported {version}!");
260 return Err(SerializationError::UnsupportedVersion);
261 } else {
262 error!("Unsuported version {version}!");
263 return Err(SerializationError::UnsupportedVersion);
264 }
265 Ok(me)
266 }
267}
268
269impl fmt::Display for TelemetryEvent {
270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271 let mut repr = String::from("<TelemetryEvent:");
272 let mut te = self.tof_event.clone();
273 te.calc_gcu_variables();
274 let tof_str = format!("\n {}", self.tof_event);
275 let mut good_hits = 0;
276
277 if self.version == 0 {
278 repr += "\n VERSION 0 NOT SUPPORTED!!";
279 } else if self.version == 1 {
280 for _ in &self.tracker_hits {
281 good_hits += 1;
282 }
283 }
284 repr += &(format!(" {}", self.header));
285 repr += "\n ** ** ** MERGED ** ** **";
286 repr += &(format!("\n version {}", self.version));
287 repr += &(format!("\n event ID {}", self.event_id));
288 repr += "\n ** ** ** TOF GCU VARIABLES ** ** **";
289 repr += &(format!("\n n_hits_umb {}", te.n_hits_umb));
290 repr += &(format!("\n n_hits_cbe {}", te.n_hits_cbe));
291 repr += &(format!("\n n_hits_cor {}", te.n_hits_cor));
292 repr += &(format!("\n tot_edep_umb {}", te.tot_edep_umb));
293 repr += &(format!("\n tot_edep_cbe {}", te.tot_edep_cbe));
294 repr += &(format!("\n tot_edep_cor {}", te.tot_edep_cor));
295 if self.version == 0 {
296 repr += "\n VERSION 0 NOT SUPPORTED!!";
297 }
298 repr += "\n ** ** ** TRACKER ** ** **";
299 if self.version == 0 {
300 repr += "\n VERSION 0 NOT SUPPORTED!!";
301 } else if self.version == 1 {
302 repr += &(format!("\n Trk oscillators {:?}", self.tracker_oscillators));
303 }
304 repr += &(format!("\n N Good Trk Hits {}", good_hits));
305 repr += &tof_str;
306 write!(f,"{}", repr)
307 }
308}
309
310#[cfg(feature="pybindings")]
313#[pymethods]
314impl TelemetryEvent {
315
316 #[getter]
317 #[pyo3(name="version")]
318 fn version_py(&self) -> u8 {
319 self.version
320 }
321
322 #[staticmethod]
323 #[pyo3(name = "get_trk_energy")]
324 fn get_trk_energy_py(adc : f32, tf : &TrackerStripTransferFunction) -> f32 {
325 Self::get_trk_energy(adc, tf)
326 }
327
328 #[getter]
329 fn get_header(&self) -> TelemetryPacketHeader {
330 self.header
331 }
332
333 #[getter]
334 fn tracker(&self) -> PyResult<Vec<TrackerHit>> {
335 Ok(self.tracker_hits.clone())
336 }
337
338 #[getter]
339 fn get_event_id(&self) -> u32 {
340 self.event_id
341 }
342
343 #[getter]
345 fn get_tof(&self) -> PyResult<TofEvent> {
346 Ok(self.tof_event.clone())
347 }
348
349 #[getter]
350 fn tracker_pointcloud(&self) -> Vec<(f32, f32, f32, f32, f32)> {
351 let mut pts = Vec::<(f32,f32,f32,f32,f32)>::new();
352 for h in &self.tracker_hits {
353 let pt = (10.0*h.x, 10.0*h.y, 10.0*h.z, f32::NAN, h.adc as f32);
356 pts.push(pt);
357 }
358 pts
359 }
360
361 #[staticmethod]
365 fn from_telemetrypacket(packet : TelemetryPacket) -> PyResult<Self> {
366 match Self::from_bytestream(&packet.payload, &mut 0) {
367 Ok(mut event) => {
368 event.header = packet.header.clone();
369 #[cfg(feature="database")]
371 event.dehydrate(&packet.tof_paddles, &packet.trk_strips);
372 return Ok(event);
373 }
374 Err(err) => {
375 return Err(PyValueError::new_err(err.to_string()));
376 }
377 }
378 }
379
380}
399
400#[cfg(feature="pybindings")]
401pythonize!(TelemetryEvent);
402