gondola_core/monitoring/
pb_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#[cfg(feature="tofcontrol")]
7use tof_control::helper::pb_type::{
8  PBTemp,
9  PBVcp
10};
11
12/// Sensors on the power boards (PB)
13///
14/// Each RAT has a single PB
15#[derive(Debug, Copy, Clone, PartialEq)]
16#[cfg_attr(feature="pybindings", pyclass)]
17pub struct PBMoniData {
18  pub board_id       : u8,
19  pub p3v6_preamp_vcp: [f32; 3],
20  pub n1v6_preamp_vcp: [f32; 3],
21  pub p3v4f_ltb_vcp  : [f32; 3],
22  pub p3v4d_ltb_vcp  : [f32; 3],
23  pub p3v6_ltb_vcp   : [f32; 3],
24  pub n1v6_ltb_vcp   : [f32; 3],
25  pub pds_temp       : f32,
26  pub pas_temp       : f32,
27  pub nas_temp       : f32,
28  pub shv_temp       : f32,
29  // will not get serialized 
30  pub timestamp      : u64,
31}
32
33impl PBMoniData {
34  pub fn new() -> Self {
35    Self {
36      board_id       : 0,
37      p3v6_preamp_vcp: [f32::MAX, f32::MAX, f32::MAX],
38      n1v6_preamp_vcp: [f32::MAX, f32::MAX, f32::MAX],
39      p3v4f_ltb_vcp  : [f32::MAX, f32::MAX, f32::MAX],
40      p3v4d_ltb_vcp  : [f32::MAX, f32::MAX, f32::MAX],
41      p3v6_ltb_vcp   : [f32::MAX, f32::MAX, f32::MAX],
42      n1v6_ltb_vcp   : [f32::MAX, f32::MAX, f32::MAX],
43      pds_temp       : f32::MAX,
44      pas_temp       : f32::MAX,
45      nas_temp       : f32::MAX,
46      shv_temp       : f32::MAX,
47      timestamp      : 0,
48    }
49  }
50  
51  #[cfg(feature = "tofcontrol")]
52  pub fn add_temps(&mut self, pbtmp : &PBTemp) {
53    self.pds_temp = pbtmp.pds_temp; 
54    self.pas_temp = pbtmp.pas_temp; 
55    self.nas_temp = pbtmp.nas_temp; 
56    self.shv_temp = pbtmp.shv_temp; 
57  }
58  
59  #[cfg(feature = "tofcontrol")]
60  pub fn add_vcp(&mut self, pbvcp : &PBVcp) {
61    self.p3v6_preamp_vcp = pbvcp.p3v6_pa_vcp; 
62    self.n1v6_preamp_vcp = pbvcp.n1v6_pa_vcp;  
63    self.p3v4f_ltb_vcp   = pbvcp.p3v4f_ltb_vcp;
64    self.p3v4d_ltb_vcp   = pbvcp.p3v4d_ltb_vcp;
65    self.p3v6_ltb_vcp    = pbvcp.p3v6_ltb_vcp;
66    self.n1v6_ltb_vcp    = pbvcp.n1v6_ltb_vcp;
67  }
68}
69
70#[cfg(feature="pybindings")]
71#[pymethods]
72impl PBMoniData {
73
74  #[getter]
75  fn get_board_id(&self) -> u8 {
76    self.board_id
77  }
78
79  #[getter]
80  #[pyo3(name="timestamp")]
81  fn get_timestamp_py(&self) -> u64 {
82    self.timestamp
83  }
84
85  #[getter]
86  fn get_p3v6_preamp_vcp(&self) -> [f32; 3] {
87    self.p3v6_preamp_vcp
88  }
89  
90  #[getter]
91  fn get_n1v6_preamp_vcp(&self) -> [f32; 3] {
92    self.n1v6_preamp_vcp
93  }
94  
95  #[getter]
96  fn get_p3v4f_ltb_vcp(&self) -> [f32; 3] {
97    self.p3v4f_ltb_vcp
98  }
99  
100  #[getter]
101  fn get_p3v4d_ltb_vcp(&self) -> [f32; 3] {
102    self.p3v4d_ltb_vcp
103  }
104  
105  #[getter]
106  fn get_p3v6_ltb_vcp(&self) -> [f32; 3] {
107    self.p3v6_ltb_vcp
108  }
109  
110  #[getter]
111  fn get_n1v6_ltb_vcp(&self) -> [f32; 3] {
112    self.n1v6_ltb_vcp
113  }
114  
115  #[getter]
116  fn get_pds_temp(&self) -> f32 {  
117    self.pds_temp
118  }
119  #[getter]
120  fn get_pas_temp(&self) -> f32 {
121    self.pas_temp
122  }
123  #[getter]
124  fn get_nas_temp(&self) -> f32 {
125    self.nas_temp
126  }
127
128  #[getter]
129  fn get_shv_temp(&self) -> f32 {
130    self.shv_temp
131  }
132}
133
134impl Default for PBMoniData {
135  fn default() -> Self {
136    Self::new()
137  }
138}
139
140impl fmt::Display for PBMoniData {
141  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142    write!(f, "<PBMoniData:
143  BOARD ID     :  {}
144  ** Temperatures **
145  PDS TMP      :  {:.2} [\u{00B0}C]
146  PAS TMP      :  {:.2} [\u{00B0}C]
147  NAS TMP      :  {:.2} [\u{00B0}C]
148  SHV TMP      :  {:.2} [\u{00B0}C]
149  ** Power **
150  P3V6  Preamp :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
151  N1V6  Preamp : {:.3}  [V] | {:.3} [A] | {:.3} [W]
152  P3V4f LTB    :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
153  P3V4d LTB    :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
154  P3V6  LTB    :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
155  N1V6  LTB    : {:.3}  [V] | {:.3} [A] | {:.3} [W]>",
156           self.board_id       , 
157           if self.pds_temp != f32::MAX {self.pds_temp.to_string()} else {String::from("f32::MAX (ERR)")},
158           if self.pas_temp != f32::MAX {self.pas_temp.to_string()} else {String::from("f32::MAX (ERR)")},
159           if self.nas_temp != f32::MAX {self.nas_temp.to_string()} else {String::from("f32::MAX (ERR)")},
160           if self.shv_temp != f32::MAX {self.shv_temp.to_string()} else {String::from("f32::MAX (ERR)")},
161           if self.p3v6_preamp_vcp[0] != f32::MAX {self.p3v6_preamp_vcp[0].to_string()} else {String::from("f32::MAX (ERR)")},
162           if self.p3v6_preamp_vcp[1] != f32::MAX {self.p3v6_preamp_vcp[1].to_string()} else {String::from("f32::MAX (ERR)")},
163           if self.p3v6_preamp_vcp[2] != f32::MAX {self.p3v6_preamp_vcp[2].to_string()} else {String::from("f32::MAX (ERR)")},
164           if self.n1v6_preamp_vcp[0] != f32::MAX {self.n1v6_preamp_vcp[0].to_string()} else {String::from("f32::MAX (ERR)")},
165           if self.n1v6_preamp_vcp[1] != f32::MAX {self.n1v6_preamp_vcp[1].to_string()} else {String::from("f32::MAX (ERR)")},
166           if self.n1v6_preamp_vcp[2] != f32::MAX {self.n1v6_preamp_vcp[2].to_string()} else {String::from("f32::MAX (ERR)")},
167           if self.p3v4f_ltb_vcp[0]   != f32::MAX {self.p3v4f_ltb_vcp[0].to_string()  } else {String::from("f32::MAX (ERR)")},
168           if self.p3v4f_ltb_vcp[1]   != f32::MAX {self.p3v4f_ltb_vcp[1].to_string()  } else {String::from("f32::MAX (ERR)")},
169           if self.p3v4f_ltb_vcp[2]   != f32::MAX {self.p3v4f_ltb_vcp[2].to_string()  } else {String::from("f32::MAX (ERR)")},
170           if self.p3v4d_ltb_vcp[0]   != f32::MAX {self.p3v4d_ltb_vcp[0].to_string()  } else {String::from("f32::MAX (ERR)")},
171           if self.p3v4d_ltb_vcp[1]   != f32::MAX {self.p3v4d_ltb_vcp[1].to_string()  } else {String::from("f32::MAX (ERR)")},
172           if self.p3v4d_ltb_vcp[2]   != f32::MAX {self.p3v4d_ltb_vcp[2].to_string()  } else {String::from("f32::MAX (ERR)")},
173           if self.p3v6_ltb_vcp[0]    != f32::MAX {self.p3v6_ltb_vcp[0].to_string()   } else {String::from("f32::MAX (ERR)")},
174           if self.p3v6_ltb_vcp[1]    != f32::MAX {self.p3v6_ltb_vcp[1].to_string()   } else {String::from("f32::MAX (ERR)")},
175           if self.p3v6_ltb_vcp[2]    != f32::MAX {self.p3v6_ltb_vcp[2].to_string()   } else {String::from("f32::MAX (ERR)")},
176           if self.n1v6_ltb_vcp[0]    != f32::MAX {self.n1v6_ltb_vcp[0].to_string()   } else {String::from("f32::MAX (ERR)")},
177           if self.n1v6_ltb_vcp[1]    != f32::MAX {self.n1v6_ltb_vcp[1].to_string()   } else {String::from("f32::MAX (ERR)")},
178           if self.n1v6_ltb_vcp[2]    != f32::MAX {self.n1v6_ltb_vcp[2].to_string()   } else {String::from("f32::MAX (ERR)")})
179  }
180}
181
182impl TofPackable for PBMoniData {
183  const TOF_PACKET_TYPE : TofPacketType = TofPacketType::PBMoniData;
184}
185
186impl MoniData for PBMoniData {
187
188  fn get_board_id(&self) -> u8 {
189    self.board_id 
190  }
191  
192  fn get_timestamp(&self) -> u64 {
193    self.timestamp 
194  }
195
196  fn set_timestamp(&mut self, ts : u64) {
197    self.timestamp = ts;
198  }
199
200  fn get(&self, varname : &str) -> Option<f32> {
201    match varname {
202      "board_id"      => Some(0.0f32),
203      "p3v6_preamp_v" => Some(self.p3v6_preamp_vcp[0]), 
204      "p3v6_preamp_c" => Some(self.p3v6_preamp_vcp[1]), 
205      "p3v6_preamp_p" => Some(self.p3v6_preamp_vcp[2]), 
206      "n1v6_preamp_v" => Some(self.n1v6_preamp_vcp[0]), 
207      "n1v6_preamp_c" => Some(self.n1v6_preamp_vcp[1]), 
208      "n1v6_preamp_p" => Some(self.n1v6_preamp_vcp[2]), 
209      "p3v4f_ltb_v"   => Some(self.p3v4f_ltb_vcp[0]), 
210      "p3v4f_ltb_c"   => Some(self.p3v4f_ltb_vcp[1]), 
211      "p3v4f_ltb_p"   => Some(self.p3v4f_ltb_vcp[2]), 
212      "p3v4d_ltb_v"   => Some(self.p3v4d_ltb_vcp[0]), 
213      "p3v4d_ltb_c"   => Some(self.p3v4d_ltb_vcp[1]), 
214      "p3v4d_ltb_p"   => Some(self.p3v4d_ltb_vcp[2]), 
215      "p3v6_ltb_v"    => Some(self.p3v6_ltb_vcp[0]), 
216      "p3v6_ltb_c"    => Some(self.p3v6_ltb_vcp[1]), 
217      "p3v6_ltb_p"    => Some(self.p3v6_ltb_vcp[2]), 
218      "n1v6_ltb_v"    => Some(self.n1v6_ltb_vcp[0]), 
219      "n1v6_ltb_c"    => Some(self.n1v6_ltb_vcp[1]), 
220      "n1v6_ltb_p"    => Some(self.n1v6_ltb_vcp[2]), 
221      "pds_temp"      => Some(self.pds_temp),
222      "pas_temp"      => Some(self.pas_temp),
223      "nas_temp"      => Some(self.nas_temp),
224      "shv_temp"      => Some(self.shv_temp),
225      "timestamp"     => Some(self.timestamp as f32),
226      _               => None, 
227    }
228  }
229
230  fn keys() -> Vec<&'static str> {
231    vec!["board_id",
232         "p3v6_preamp_v", "p3v6_preamp_c", "p3v6_preamp_p",
233         "n1v6_preamp_v", "n1v6_preamp_c", "n1v6_preamp_p",
234         "p3v4f_ltb_v", "p3v4f_ltb_c", "p3v4f_ltb_p",
235         "p3v4d_ltb_v", "p3v4d_ltb_c", "p3v4d_ltb_p",
236         "p3v6_ltb_v", "p3v6_ltb_c", "p3v6_ltb_p",
237         "n1v6_ltb_v", "n1v6_ltb_c", "n1v6_ltb_p",
238         "pds_temp", "pas_temp", "nas_temp", "shv_temp","timestamp"]
239  }
240}
241
242
243impl Serialization for PBMoniData {
244  const HEAD : u16 = 0xAAAA;
245  const TAIL : u16 = 0x5555;
246  /// The data size when serialized to a bytestream
247  /// This needs to be updated when we change the 
248  /// packet layout, e.g. add new members.
249  /// HEAD + TAIL + sum(sizeof(m) for m in _all_members_))
250  const SIZE : usize  = 89 + 4; // 4 header + footer
251  
252  fn to_bytestream(&self) -> Vec<u8> {
253    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
254    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
255    stream.extend_from_slice(&self.board_id          .to_le_bytes());
256    stream.extend_from_slice(&self.p3v6_preamp_vcp[0].to_le_bytes());
257    stream.extend_from_slice(&self.p3v6_preamp_vcp[1].to_le_bytes());
258    stream.extend_from_slice(&self.p3v6_preamp_vcp[2].to_le_bytes());
259    stream.extend_from_slice(&self.n1v6_preamp_vcp[0].to_le_bytes());
260    stream.extend_from_slice(&self.n1v6_preamp_vcp[1].to_le_bytes());
261    stream.extend_from_slice(&self.n1v6_preamp_vcp[2].to_le_bytes());
262    stream.extend_from_slice(&self.p3v4f_ltb_vcp[0]  .to_le_bytes());
263    stream.extend_from_slice(&self.p3v4f_ltb_vcp[1]  .to_le_bytes());
264    stream.extend_from_slice(&self.p3v4f_ltb_vcp[2]  .to_le_bytes());
265    stream.extend_from_slice(&self.p3v4d_ltb_vcp[0]  .to_le_bytes());
266    stream.extend_from_slice(&self.p3v4d_ltb_vcp[1]  .to_le_bytes());
267    stream.extend_from_slice(&self.p3v4d_ltb_vcp[2]  .to_le_bytes());
268    stream.extend_from_slice(&self.p3v6_ltb_vcp[0]   .to_le_bytes());
269    stream.extend_from_slice(&self.p3v6_ltb_vcp[1]   .to_le_bytes());
270    stream.extend_from_slice(&self.p3v6_ltb_vcp[2]   .to_le_bytes());
271    stream.extend_from_slice(&self.n1v6_ltb_vcp[0]   .to_le_bytes());
272    stream.extend_from_slice(&self.n1v6_ltb_vcp[1]   .to_le_bytes());
273    stream.extend_from_slice(&self.n1v6_ltb_vcp[2]   .to_le_bytes());
274    stream.extend_from_slice(&self.pds_temp          .to_le_bytes());
275    stream.extend_from_slice(&self.pas_temp          .to_le_bytes());
276    stream.extend_from_slice(&self.nas_temp          .to_le_bytes());
277    stream.extend_from_slice(&self.shv_temp          .to_le_bytes());
278    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
279    stream
280  } 
281
282  fn from_bytestream(stream    : &Vec<u8>, 
283                     pos       : &mut usize) 
284    -> Result<PBMoniData, SerializationError>{
285    Self::verify_fixed(stream, pos)?;
286    let mut moni            = PBMoniData::new();
287    moni.board_id           = parse_u8(stream, pos) ; 
288    moni.p3v6_preamp_vcp[0] = parse_f32(stream, pos);
289    moni.p3v6_preamp_vcp[1] = parse_f32(stream, pos);
290    moni.p3v6_preamp_vcp[2] = parse_f32(stream, pos);
291    moni.n1v6_preamp_vcp[0] = parse_f32(stream, pos);
292    moni.n1v6_preamp_vcp[1] = parse_f32(stream, pos);
293    moni.n1v6_preamp_vcp[2] = parse_f32(stream, pos);
294    moni.p3v4f_ltb_vcp[0]   = parse_f32(stream, pos);
295    moni.p3v4f_ltb_vcp[1]   = parse_f32(stream, pos);
296    moni.p3v4f_ltb_vcp[2]   = parse_f32(stream, pos);
297    moni.p3v4d_ltb_vcp[0]   = parse_f32(stream, pos);
298    moni.p3v4d_ltb_vcp[1]   = parse_f32(stream, pos);
299    moni.p3v4d_ltb_vcp[2]   = parse_f32(stream, pos);
300    moni.p3v6_ltb_vcp[0]    = parse_f32(stream, pos);
301    moni.p3v6_ltb_vcp[1]    = parse_f32(stream, pos);
302    moni.p3v6_ltb_vcp[2]    = parse_f32(stream, pos);
303    moni.n1v6_ltb_vcp[0]    = parse_f32(stream, pos);
304    moni.n1v6_ltb_vcp[1]    = parse_f32(stream, pos);
305    moni.n1v6_ltb_vcp[2]    = parse_f32(stream, pos);
306    moni.pds_temp           = parse_f32(stream, pos);
307    moni.pas_temp           = parse_f32(stream, pos);
308    moni.nas_temp           = parse_f32(stream, pos);
309    moni.shv_temp           = parse_f32(stream, pos);
310    *pos += 2;// account for tail
311    Ok(moni)
312  }
313}
314
315#[cfg(feature = "random")]
316impl FromRandom for PBMoniData {
317    
318  fn from_random() -> PBMoniData {
319    let mut moni = Self::new();
320    let mut rng = rand::rng();
321    moni.board_id           = rng.random::<u8>(); 
322    for k in 0..3 {
323      let foo = rng.random::<f32>();
324      moni.p3v6_preamp_vcp[k] = foo;
325    }
326    for k in 0..3 {
327      let foo = rng.random::<f32>();
328      moni.n1v6_preamp_vcp[k] = foo;
329    }
330    for k in 0..3 {
331      let foo = rng.random::<f32>();
332      moni.p3v4f_ltb_vcp[k] = foo;
333    }
334    for k in 0..3 {
335      let foo = rng.random::<f32>();
336      moni.p3v4d_ltb_vcp[k] = foo;
337    }
338    for k in 0..3 {
339      let foo = rng.random::<f32>();
340      moni.p3v6_ltb_vcp[k] = foo;
341    }
342    for k in 0..3 {
343      let foo = rng.random::<f32>();
344      moni.n1v6_ltb_vcp[k] = foo;
345    }
346    moni.pds_temp = rng.random::<f32>(); 
347    moni.pas_temp = rng.random::<f32>(); 
348    moni.nas_temp = rng.random::<f32>(); 
349    moni.shv_temp = rng.random::<f32>(); 
350    moni
351  }
352}
353
354//----------------------------------------
355
356moniseries!(PBMoniDataSeries, PBMoniData);
357
358#[cfg(feature="pybindings")]
359pythonize_packable!(PBMoniData);
360
361#[cfg(feature="pybindings")]
362pythonize_monidata!(PBMoniData);
363
364//----------------------------------------
365
366#[test]
367#[cfg(feature = "random")]
368fn pack_pbmonidata() {
369  for _ in 0..100 {
370    let data = PBMoniData::from_random();
371    let test : PBMoniData = data.pack().unpack().unwrap();
372    assert_eq!(data, test);
373  }
374}
375