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 tof_str = format!("\n {}", self.tof_event);
273 let mut good_hits = 0;
274 if self.version == 0 {
275 repr += "\n VERSION 0 NOT SUPPORTED!!";
276 } else if self.version == 1 {
277 for _ in &self.tracker_hits {
278 good_hits += 1;
279 }
280 }
281 repr += &(format!(" {}", self.header));
282 repr += "\n ** ** ** MERGED ** ** **";
283 repr += &(format!("\n version {}", self.version));
284 repr += &(format!("\n event ID {}", self.event_id));
285 if self.version == 0 {
286 repr += "\n VERSION 0 NOT SUPPORTED!!";
287 }
288 repr += "\n ** ** ** TRACKER ** ** **";
289 if self.version == 0 {
290 repr += "\n VERSION 0 NOT SUPPORTED!!";
291 } else if self.version == 1 {
292 repr += &(format!("\n Trk oscillators {:?}", self.tracker_oscillators));
293 }
294 repr += &(format!("\n N Good Trk Hits {}", good_hits));
295 repr += &tof_str;
296 write!(f,"{}", repr)
297 }
298}
299
300#[cfg(feature="pybindings")]
303#[pymethods]
304impl TelemetryEvent {
305
306 #[getter]
307 #[pyo3(name="version")]
308 fn version_py(&self) -> u8 {
309 self.version
310 }
311
312 #[staticmethod]
313 #[pyo3(name = "get_trk_energy")]
314 fn get_trk_energy_py(adc : f32, tf : &TrackerStripTransferFunction) -> f32 {
315 Self::get_trk_energy(adc, tf)
316 }
317
318 #[getter]
319 fn get_header(&self) -> TelemetryPacketHeader {
320 self.header
321 }
322
323 #[getter]
324 fn tracker(&self) -> PyResult<Vec<TrackerHit>> {
325 Ok(self.tracker_hits.clone())
326 }
327
328 #[getter]
329 fn get_event_id(&self) -> u32 {
330 self.event_id
331 }
332
333 #[getter]
335 fn get_tof(&self) -> PyResult<TofEvent> {
336 Ok(self.tof_event.clone())
337 }
338
339 #[getter]
340 fn tracker_pointcloud(&self) -> Vec<(f32, f32, f32, f32, f32)> {
341 let mut pts = Vec::<(f32,f32,f32,f32,f32)>::new();
342 for h in &self.tracker_hits {
343 let pt = (10.0*h.x, 10.0*h.y, 10.0*h.z, f32::NAN, h.adc as f32);
346 pts.push(pt);
347 }
348 pts
349 }
350
351 #[staticmethod]
355 fn from_telemetrypacket(packet : TelemetryPacket) -> PyResult<Self> {
356 match Self::from_bytestream(&packet.payload, &mut 0) {
357 Ok(mut event) => {
358 event.header = packet.header.clone();
359 return Ok(event);
360 }
361 Err(err) => {
362 return Err(PyValueError::new_err(err.to_string()));
363 }
364 }
365 }
366
367}
386
387#[cfg(feature="pybindings")]
388pythonize!(TelemetryEvent);
389