Skip to main content

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