gondola_core/monitoring/
mtb_moni_data.rs

1// This file is part of gaps-online-software and published 
2// under the GPLv3 license
3
4use crate::prelude::*;
5
6/// Monitoring the MTB
7#[derive(Debug, Copy, Clone, PartialEq)]
8#[cfg_attr(feature="pybindings", pyclass)]
9pub struct MtbMoniData {
10  pub tiu_busy_len : u32,
11  /// tiu_status\[0\] = emu_mode
12  /// tiu_status\[1\] = use_aux_link
13  /// tiu_status\[2\] = tiu_bad
14  /// tiu_status\[3\] = bsy_stuck
15  /// tiu_status\[4\] = ignore_bsy
16  pub tiu_status   : u8,
17  ///// Prescale factor in per cent
18  ///// (might not be accurate)
19  //pub prescale     : f16,
20  //pub rsvd         : u8,
21  pub daq_queue_len: u16,
22  //pub vccpaux      : u16, 
23  //pub vccoddr      : u16, 
24  pub temp         : u16, 
25  /// Unfortunatly at this point we only have
26  /// a single byte left
27  pub rb_lost_rate : u8,
28  pub rate         : u16, 
29  pub lost_rate    : u16, 
30  pub vccint       : u16, 
31  pub vccbram      : u16, 
32  pub vccaux       : u16, 
33  // will not get serialized
34  pub timestamp    : u64,
35}
36
37impl MtbMoniData {
38  
39  pub fn new() -> Self {
40    Self {
41      tiu_busy_len  : u32::MAX,
42      tiu_status    : u8::MAX,
43      //rsvd          : u8::MAX,
44      //prescale      : f16::MAX,
45      daq_queue_len : u16::MAX,
46      temp          : u16::MAX,
47      vccint        : u16::MAX,
48      vccaux        : u16::MAX,
49      vccbram       : u16::MAX,
50      rate          : u16::MAX,
51      lost_rate     : u16::MAX,
52      rb_lost_rate  : u8::MAX,
53      timestamp     : 0,
54    }
55  }
56
57  pub fn get_tiu_emulation_mode(&self) -> bool {
58    self.tiu_status & 0x1 > 0
59  }
60  
61  pub fn get_tiu_use_aux_link(&self) -> bool {
62    self.tiu_status & 0x2 > 0
63  }
64
65  pub fn get_tiu_bad(&self) -> bool { 
66    self.tiu_status & 0x4 > 0
67  }
68
69  pub fn get_tiu_busy_stuck(&self) -> bool {
70    self.tiu_status & 0x8 > 0
71  }
72
73  pub fn get_tiu_ignore_busy(&self) -> bool {
74    self.tiu_status & 0x10 > 0
75  }
76
77
78  /// Convert ADC temp from adc values to Celsius
79  pub fn get_fpga_temp(&self) -> f32 {
80    self.temp as f32 * 503.975 / 4096.0 - 273.15
81  }
82  
83  /// Convert ADC VCCINT from adc values to Voltage
84  pub fn adc_vcc_conversion(data : u16) -> f32 {
85    3.0 * data as f32 / (2_u32.pow(12-1)) as f32
86  }
87
88  //pub fn set_prescale(&mut self, prescale : f32) {
89  //  self.prescale = f16::from_f32(prescale);
90  //}
91
92  //pub fn get_prescale(&self) -> f32 {
93  //  self.prescale.to_f32()  
94  //}
95}
96
97impl Default for MtbMoniData {
98  fn default() -> Self {
99    Self::new()
100  }
101}
102
103impl fmt::Display for MtbMoniData {
104  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105    write!(f, "<MtbMoniData:
106  MTB  EVT RATE  [Hz] {}
107  LOST EVT RATE  [Hz] {}
108  LOST RB EVT R  [Hz] {}
109  TIU BUSY CNT  [CLK] {}
110  DAQ QUEUE LEN       {}
111  --- TIU STATUS ---
112    EMU MODE          {}
113    USE AUX LINK      {}
114    TIU BAD           {}
115    BUSY STUCK        {}
116    IGNORE BUSY       {}
117  --- --- --- --- --
118  FPGA TEMP      [\u{00B0}C] {:.2}
119  VCCINT          [V] {:.3}
120  VCCAUX          [V] {:.3},
121  VCCBRAM         [V] {:.3}>",
122           self.rate,
123           self.lost_rate,
124           self.rb_lost_rate,
125           self.tiu_busy_len,
126           self.daq_queue_len,
127           //self.get_prescale(),
128           self.get_tiu_emulation_mode(),
129           self.get_tiu_use_aux_link(),
130           self.get_tiu_bad(),
131           self.get_tiu_busy_stuck(),
132           self.get_tiu_ignore_busy(),
133           self.get_fpga_temp(),
134           Self::adc_vcc_conversion(self.vccint    ),
135           Self::adc_vcc_conversion(self.vccaux    ),
136           Self::adc_vcc_conversion(self.vccbram   ),
137           )
138  }
139}
140
141impl TofPackable for MtbMoniData {
142  const TOF_PACKET_TYPE : TofPacketType = TofPacketType::MtbMoniData;
143}
144
145impl Serialization for MtbMoniData {
146  
147  const SIZE : usize = 24;
148  const HEAD : u16   = 0xAAAA;
149  const TAIL : u16   = 0x5555;
150
151  fn to_bytestream(&self) -> Vec<u8> {
152    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
153    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
154    stream.extend_from_slice(&self.tiu_busy_len.to_le_bytes());
155    stream.extend_from_slice(&self.tiu_status .to_le_bytes());
156    //stream.extend_from_slice(&self.rsvd.to_le_bytes());
157    stream.extend_from_slice(&self.rb_lost_rate.to_le_bytes());
158    stream.extend_from_slice(&self.daq_queue_len.to_le_bytes());
159    stream.extend_from_slice(&self.temp       .to_le_bytes());
160    stream.extend_from_slice(&self.vccint     .to_le_bytes()); 
161    stream.extend_from_slice(&self.vccaux     .to_le_bytes()); 
162    stream.extend_from_slice(&self.vccbram    .to_le_bytes()); 
163    //stream.extend_from_slice(&self.prescale   .to_le_bytes());
164    //stream.extend_from_slice(&self.rb_lost_rate.to_le_bytes());
165    stream.extend_from_slice(&self.rate       .to_le_bytes()); 
166    stream.extend_from_slice(&self.lost_rate  .to_le_bytes());
167    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
168    stream
169  }
170
171  fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
172    -> Result<Self, SerializationError> {
173    let mut moni_data      = Self::new();
174    Self::verify_fixed(stream, pos)?;
175    moni_data.tiu_busy_len  = parse_u32(&stream, pos);
176    moni_data.tiu_status    = parse_u8(&stream, pos);
177    //moni_data.rsvd          = parse_u8(&stream, pos);
178    moni_data.rb_lost_rate  = parse_u8(&stream, pos);
179    moni_data.daq_queue_len = parse_u16(&stream, pos);
180    moni_data.temp          = parse_u16(&stream, pos);
181    moni_data.vccint        = parse_u16(&stream, pos);
182    //moni_data.prescale      = parse_f16(&stream, pos);
183    moni_data.vccaux        = parse_u16(&stream, pos);
184    moni_data.vccbram       = parse_u16(&stream, pos);
185    //moni_data.rb_lost_rate  = parse_u16(&stream, pos);
186    moni_data.rate          = parse_u16(&stream, pos);
187    moni_data.lost_rate     = parse_u16(&stream, pos);
188    *pos += 2; // since we deserialized the tail earlier and 
189              // didn't account for it
190    Ok(moni_data)
191  }
192}
193
194impl MoniData for MtbMoniData {
195
196  fn get_timestamp(&self) -> u64 {
197    self.timestamp
198  }
199
200  fn set_timestamp(&mut self, ts : u64) {
201    self.timestamp = ts;
202  }
203
204  fn get_board_id(&self) -> u8 {
205    return 0;
206  }
207  
208  fn get(&self, varname : &str) -> Option<f32> {
209    match varname {
210      "board_id"     => Some(0.0f32),
211      "tiu_busy_len" => Some(self.tiu_busy_len as f32), 
212      "tiu_status"   => Some(self.tiu_status as f32), 
213      "daq_queue_len"  => Some(self.daq_queue_len as f32), 
214      //"prescale"     => Some(self.get_prescale()),
215      "temp"         => Some(self.get_fpga_temp()), 
216      "vccint"       => Some(Self::adc_vcc_conversion(self.vccint)), 
217      "vccaux"       => Some(Self::adc_vcc_conversion(self.vccaux)), 
218      "vccbram"      => Some(Self::adc_vcc_conversion(self.vccbram)), 
219      "rate"         => Some(self.rate as f32), 
220      "lost_rate"    => Some(self.lost_rate as f32), 
221      "rb_lost_rate" => Some(self.rb_lost_rate as f32), 
222      "timestamp"    => Some(self.timestamp as f32),
223      _              => None
224    }
225  }
226  
227  fn keys() -> Vec<&'static str> {
228    vec![
229      "board_id"      ,  
230      "tiu_busy_len"  , 
231      "tiu_status"    , 
232      "daq_queue_len" , 
233      "temp"          , 
234      "vccint"        , 
235      "vccaux"        , 
236      "vccbram"       , 
237      "rb_lost_rate"  ,
238      "rate"          , 
239      "lost_rate",
240      "timestamp"] 
241  }
242}
243
244#[cfg(feature = "random")]
245impl FromRandom for MtbMoniData {
246  fn from_random() -> Self {
247    let mut moni      = Self::new();
248    let mut rng       = rand::rng();
249    moni.tiu_busy_len = rng.random::<u32>();
250    moni.tiu_status   = rng.random::<u8>();
251    //moni.prescale     = f16::from_f32(rng.random::<f32>());
252    moni.daq_queue_len= rng.random::<u16>();
253    moni.temp         = rng.random::<u16>();
254    moni.vccint       = rng.random::<u16>();
255    moni.vccaux       = rng.random::<u16>();
256    moni.vccbram      = rng.random::<u16>();
257    moni.rb_lost_rate = rng.random::<u8>();
258    moni.rate         = rng.random::<u16>();
259    moni.lost_rate    = rng.random::<u16>();
260    moni.timestamp    = 0;
261    moni
262  }
263}
264
265#[cfg(feature="pybindings")]
266#[pymethods]
267impl MtbMoniData {
268  
269  #[getter]
270  fn get_vccint(&self) -> f32 {
271    Self::adc_vcc_conversion(self.vccint)
272  }
273
274  #[getter]
275  fn get_vccbram(&self) -> f32 {
276    Self::adc_vcc_conversion(self.vccbram)
277  }
278
279  #[getter]
280  fn get_vccaux(&self) -> f32 {
281    Self::adc_vcc_conversion(self.vccaux)
282  }
283
284  #[getter]
285  pub fn get_rate(&self) -> u16 {
286    self.rate
287  }
288  
289  #[getter]
290  pub fn get_lost_rate(&self) -> u16 {
291    self.lost_rate
292  }
293
294  #[getter]
295  /// Length of the received BUSY signal from 
296  /// the TIU in nanoseconds
297  pub fn get_tiu_busy_len(&self) -> u32 {
298    self.tiu_busy_len * 10
299  }
300
301  #[getter]
302  pub fn get_daq_queue_len(&self) -> u16 {
303    self.daq_queue_len
304  }
305
306  #[getter]
307  #[pyo3(name="tiu_emulation_mode")]
308  pub fn get_tiu_emulation_mode_py(&self) -> bool {
309    self.get_tiu_emulation_mode()
310  }
311  
312  #[getter]
313  #[pyo3(name="tiu_use_aux_link")]
314  pub fn get_tiu_use_aux_link_py(&self) -> bool {
315    self.get_tiu_use_aux_link()
316  }
317
318  #[getter]
319  #[pyo3(name="tiu_bad")]
320  pub fn get_tiu_bad_py(&self) -> bool { 
321    self.get_tiu_bad()
322  }
323
324  #[getter]
325  #[pyo3(name="tiu_busy_stuck")]
326  pub fn get_tiu_busy_stuck_py(&self) -> bool {
327    self.get_tiu_busy_stuck()
328  }
329
330  #[getter]
331  #[pyo3(name="tiu_ignore_busy")]
332  pub fn get_tiu_ignore_busy_py(&self) -> bool {
333    self.get_tiu_ignore_busy()
334  }
335
336
337  #[getter]
338  #[pyo3(name="fpga_temp")]
339  pub fn get_fpga_temp_py(&self) -> f32 {
340    self.get_fpga_temp()
341  }
342  
343  #[getter]
344  pub fn get_timestamp(&self) -> u64 {
345    self.timestamp
346  }
347}
348
349//----------------------------------------
350
351// make it available as a monidata series
352moniseries!(MtbMoniDataSeries, MtbMoniData);
353
354#[cfg(feature="pybindings")]
355pythonize_packable!(MtbMoniData);
356
357#[cfg(feature="pybindings")]
358pythonize_monidata!(MtbMoniData);
359
360//----------------------------------------
361
362#[test]
363#[cfg(feature = "random")]
364fn pack_mtbmonidata() {
365  for _ in 0..100 {
366    let data = MtbMoniData::from_random();
367    let test : MtbMoniData = data.pack().unpack().unwrap();
368    assert_eq!(data, test);
369  }
370}
371