tof_dataclasses/
monitoring.rs

1//! Tof housekeeping/monitoring
2//!
3//! Contains structs to hold monitoring
4//! information for the different parts
5//! of the TOF, e.g. RB,LTB,MTB
6//!
7//! An overview of the sensors in the 
8//! GAPS TOF can be found in the 
9//! [GAPS wiki](https://gaps1.astro.ucla.edu/wiki/gaps/index.php?title=TOF_environmental_sensors)
10
11use std::fmt;
12//use std::collections::HashMap;
13
14//use half::f16;
15
16use crate::packets::PacketType;
17
18cfg_if::cfg_if! {
19  if #[cfg(feature = "random")]  {
20    use crate::FromRandom;
21    extern crate rand;
22    use rand::Rng;
23  }
24}
25
26// Takeru's tofcontrol code
27#[cfg(feature = "tofcontrol")]
28use tof_control::helper::cpu_type::{
29    CPUTempDebug,
30    CPUInfoDebug,
31};
32
33#[cfg(feature = "tofcontrol")]
34use tof_control::helper::rb_type::{
35    RBTemp,
36    RBMag,
37    RBVcp,
38    RBPh,
39};
40
41
42#[cfg(feature = "tofcontrol")]
43use tof_control::helper::ltb_type::{
44    LTBTemp,
45    LTBThreshold,
46};
47
48#[cfg(feature = "tofcontrol")]
49use tof_control::helper::pa_type::{
50    PATemp,
51    PAReadBias,
52};
53
54#[cfg(feature = "tofcontrol")]
55use tof_control::helper::pb_type::{
56    PBTemp,
57    PBVcp,
58};
59
60use crate::serialization::{
61    Serialization,
62    SerializationError,
63    Packable,
64    parse_u8,
65    parse_u16,
66    parse_u32,
67    //parse_f16,
68    parse_f32
69};
70
71// re-export
72pub use crate::series::{
73  MoniSeries,
74  PAMoniDataSeries,
75  PBMoniDataSeries,
76  LTBMoniDataSeries,
77  RBMoniDataSeries
78};
79
80/// Monitoring data shall share the same kind 
81/// of interface. 
82pub trait MoniData {
83  /// Monitoring data is always tied to a specific
84  /// board. This might not be its own board, but 
85  /// maybe the RB the data was gathered from
86  /// This is an unique identifier for the 
87  /// monitoring data
88  fn get_board_id(&self) -> u8;
89  
90  /// Access the (data) members by name 
91  fn get(&self, varname : &str) -> Option<f32>;
92
93  /// A list of the variables in this MoniData
94  fn keys() -> Vec<&'static str>;
95}
96
97/// Sensors on the power boards (PB)
98///
99/// Each RAT has a single PB
100#[derive(Debug, Copy, Clone, PartialEq)]
101pub struct PBMoniData {
102  pub board_id       : u8,
103  pub p3v6_preamp_vcp: [f32; 3],
104  pub n1v6_preamp_vcp: [f32; 3],
105  pub p3v4f_ltb_vcp  : [f32; 3],
106  pub p3v4d_ltb_vcp  : [f32; 3],
107  pub p3v6_ltb_vcp   : [f32; 3],
108  pub n1v6_ltb_vcp   : [f32; 3],
109  pub pds_temp       : f32,
110  pub pas_temp       : f32,
111  pub nas_temp       : f32,
112  pub shv_temp       : f32,
113}
114
115impl PBMoniData {
116  pub fn new() -> Self {
117    Self {
118      board_id       : 0,
119      p3v6_preamp_vcp: [f32::MAX, f32::MAX, f32::MAX],
120      n1v6_preamp_vcp: [f32::MAX, f32::MAX, f32::MAX],
121      p3v4f_ltb_vcp  : [f32::MAX, f32::MAX, f32::MAX],
122      p3v4d_ltb_vcp  : [f32::MAX, f32::MAX, f32::MAX],
123      p3v6_ltb_vcp   : [f32::MAX, f32::MAX, f32::MAX],
124      n1v6_ltb_vcp   : [f32::MAX, f32::MAX, f32::MAX],
125      pds_temp       : f32::MAX,
126      pas_temp       : f32::MAX,
127      nas_temp       : f32::MAX,
128      shv_temp       : f32::MAX,
129    }
130  }
131  
132  #[cfg(feature = "tofcontrol")]
133  pub fn add_temps(&mut self, pbtmp : &PBTemp) {
134    self.pds_temp = pbtmp.pds_temp; 
135    self.pas_temp = pbtmp.pas_temp; 
136    self.nas_temp = pbtmp.nas_temp; 
137    self.shv_temp = pbtmp.shv_temp; 
138  }
139  
140  #[cfg(feature = "tofcontrol")]
141  pub fn add_vcp(&mut self, pbvcp : &PBVcp) {
142    self.p3v6_preamp_vcp = pbvcp.p3v6_pa_vcp; 
143    self.n1v6_preamp_vcp = pbvcp.n1v6_pa_vcp;  
144    self.p3v4f_ltb_vcp   = pbvcp.p3v4f_ltb_vcp;
145    self.p3v4d_ltb_vcp   = pbvcp.p3v4d_ltb_vcp;
146    self.p3v6_ltb_vcp    = pbvcp.p3v6_ltb_vcp;
147    self.n1v6_ltb_vcp    = pbvcp.n1v6_ltb_vcp;
148  }
149
150}
151
152impl Default for PBMoniData {
153  fn default() -> Self {
154    Self::new()
155  }
156}
157
158impl fmt::Display for PBMoniData {
159  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160    write!(f, "<PBMoniData:
161  BOARD ID     :  {}
162  ** Temperatures **
163  PDS TMP      :  {:.2} [\u{00B0}C]
164  PAS TMP      :  {:.2} [\u{00B0}C]
165  NAS TMP      :  {:.2} [\u{00B0}C]
166  SHV TMP      :  {:.2} [\u{00B0}C]
167  ** Power **
168  P3V6  Preamp :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
169  N1V6  Preamp : {:.3}  [V] | {:.3} [A] | {:.3} [W]
170  P3V4f LTB    :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
171  P3V4d LTB    :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
172  P3V6  LTB    :  {:.3}  [V] | {:.3} [A] | {:.3} [W]
173  N1V6  LTB    : {:.3}  [V] | {:.3} [A] | {:.3} [W]>",
174           self.board_id       , 
175           if self.pds_temp != f32::MAX {self.pds_temp.to_string()} else {String::from("f32::MAX (ERR)")},
176           if self.pas_temp != f32::MAX {self.pas_temp.to_string()} else {String::from("f32::MAX (ERR)")},
177           if self.nas_temp != f32::MAX {self.nas_temp.to_string()} else {String::from("f32::MAX (ERR)")},
178           if self.shv_temp != f32::MAX {self.shv_temp.to_string()} else {String::from("f32::MAX (ERR)")},
179           if self.p3v6_preamp_vcp[0] != f32::MAX {self.p3v6_preamp_vcp[0].to_string()} else {String::from("f32::MAX (ERR)")},
180           if self.p3v6_preamp_vcp[1] != f32::MAX {self.p3v6_preamp_vcp[1].to_string()} else {String::from("f32::MAX (ERR)")},
181           if self.p3v6_preamp_vcp[2] != f32::MAX {self.p3v6_preamp_vcp[2].to_string()} else {String::from("f32::MAX (ERR)")},
182           if self.n1v6_preamp_vcp[0] != f32::MAX {self.n1v6_preamp_vcp[0].to_string()} else {String::from("f32::MAX (ERR)")},
183           if self.n1v6_preamp_vcp[1] != f32::MAX {self.n1v6_preamp_vcp[1].to_string()} else {String::from("f32::MAX (ERR)")},
184           if self.n1v6_preamp_vcp[2] != f32::MAX {self.n1v6_preamp_vcp[2].to_string()} else {String::from("f32::MAX (ERR)")},
185           if self.p3v4f_ltb_vcp[0]   != f32::MAX {self.p3v4f_ltb_vcp[0].to_string()  } else {String::from("f32::MAX (ERR)")},
186           if self.p3v4f_ltb_vcp[1]   != f32::MAX {self.p3v4f_ltb_vcp[1].to_string()  } else {String::from("f32::MAX (ERR)")},
187           if self.p3v4f_ltb_vcp[2]   != f32::MAX {self.p3v4f_ltb_vcp[2].to_string()  } else {String::from("f32::MAX (ERR)")},
188           if self.p3v4d_ltb_vcp[0]   != f32::MAX {self.p3v4d_ltb_vcp[0].to_string()  } else {String::from("f32::MAX (ERR)")},
189           if self.p3v4d_ltb_vcp[1]   != f32::MAX {self.p3v4d_ltb_vcp[1].to_string()  } else {String::from("f32::MAX (ERR)")},
190           if self.p3v4d_ltb_vcp[2]   != f32::MAX {self.p3v4d_ltb_vcp[2].to_string()  } else {String::from("f32::MAX (ERR)")},
191           if self.p3v6_ltb_vcp[0]    != f32::MAX {self.p3v6_ltb_vcp[0].to_string()   } else {String::from("f32::MAX (ERR)")},
192           if self.p3v6_ltb_vcp[1]    != f32::MAX {self.p3v6_ltb_vcp[1].to_string()   } else {String::from("f32::MAX (ERR)")},
193           if self.p3v6_ltb_vcp[2]    != f32::MAX {self.p3v6_ltb_vcp[2].to_string()   } else {String::from("f32::MAX (ERR)")},
194           if self.n1v6_ltb_vcp[0]    != f32::MAX {self.n1v6_ltb_vcp[0].to_string()   } else {String::from("f32::MAX (ERR)")},
195           if self.n1v6_ltb_vcp[1]    != f32::MAX {self.n1v6_ltb_vcp[1].to_string()   } else {String::from("f32::MAX (ERR)")},
196           if self.n1v6_ltb_vcp[2]    != f32::MAX {self.n1v6_ltb_vcp[2].to_string()   } else {String::from("f32::MAX (ERR)")})
197  }
198}
199
200impl Packable for PBMoniData {
201  const PACKET_TYPE : PacketType = PacketType::PBMoniData;
202}
203
204impl MoniData for PBMoniData {
205
206  fn get_board_id(&self) -> u8 {
207    self.board_id 
208  }
209  
210  fn get(&self, varname : &str) -> Option<f32> {
211    match varname {
212      "board_id"      => Some(0.0f32),
213      "p3v6_preamp_v" => Some(self.p3v6_preamp_vcp[0]), 
214      "p3v6_preamp_c" => Some(self.p3v6_preamp_vcp[1]), 
215      "p3v6_preamp_p" => Some(self.p3v6_preamp_vcp[2]), 
216      "n1v6_preamp_v" => Some(self.n1v6_preamp_vcp[0]), 
217      "n1v6_preamp_c" => Some(self.n1v6_preamp_vcp[1]), 
218      "n1v6_preamp_p" => Some(self.n1v6_preamp_vcp[2]), 
219      "p3v4f_ltb_v"   => Some(self.p3v4f_ltb_vcp[0]), 
220      "p3v4f_ltb_c"   => Some(self.p3v4f_ltb_vcp[1]), 
221      "p3v4f_ltb_p"   => Some(self.p3v4f_ltb_vcp[2]), 
222      "p3v4d_ltb_v"   => Some(self.p3v4d_ltb_vcp[0]), 
223      "p3v4d_ltb_c"   => Some(self.p3v4d_ltb_vcp[1]), 
224      "p3v4d_ltb_p"   => Some(self.p3v4d_ltb_vcp[2]), 
225      "p3v6_ltb_v"    => Some(self.p3v6_ltb_vcp[0]), 
226      "p3v6_ltb_c"    => Some(self.p3v6_ltb_vcp[1]), 
227      "p3v6_ltb_p"    => Some(self.p3v6_ltb_vcp[2]), 
228      "n1v6_ltb_v"    => Some(self.n1v6_ltb_vcp[0]), 
229      "n1v6_ltb_c"    => Some(self.n1v6_ltb_vcp[1]), 
230      "n1v6_ltb_p"    => Some(self.n1v6_ltb_vcp[2]), 
231      "pds_temp"      => Some(self.pds_temp),
232      "pas_temp"      => Some(self.pas_temp),
233      "nas_temp"      => Some(self.nas_temp),
234      "shv_temp"      => Some(self.shv_temp),
235      _               => None, 
236    }
237  }
238
239  fn keys() -> Vec<&'static str> {
240    vec!["board_id",
241         "p3v6_preamp_v", "p3v6_preamp_c", "p3v6_preamp_p",
242         "n1v6_preamp_v", "n1v6_preamp_c", "n1v6_preamp_p",
243         "p3v4f_ltb_v", "p3v4f_ltb_c", "p3v4f_ltb_p",
244         "p3v4d_ltb_v", "p3v4d_ltb_c", "p3v4d_ltb_p",
245         "p3v6_ltb_v", "p3v6_ltb_c", "p3v6_ltb_p",
246         "n1v6_ltb_v", "n1v6_ltb_c", "n1v6_ltb_p",
247         "pds_temp", "pas_temp", "nas_temp", "shv_temp"]
248  }
249}
250
251
252impl Serialization for PBMoniData {
253  const HEAD : u16 = 0xAAAA;
254  const TAIL : u16 = 0x5555;
255  /// The data size when serialized to a bytestream
256  /// This needs to be updated when we change the 
257  /// packet layout, e.g. add new members.
258  /// HEAD + TAIL + sum(sizeof(m) for m in _all_members_))
259  const SIZE : usize  = 89 + 4; // 4 header + footer
260  
261  fn to_bytestream(&self) -> Vec<u8> {
262    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
263    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
264    stream.extend_from_slice(&self.board_id          .to_le_bytes());
265    stream.extend_from_slice(&self.p3v6_preamp_vcp[0].to_le_bytes());
266    stream.extend_from_slice(&self.p3v6_preamp_vcp[1].to_le_bytes());
267    stream.extend_from_slice(&self.p3v6_preamp_vcp[2].to_le_bytes());
268    stream.extend_from_slice(&self.n1v6_preamp_vcp[0].to_le_bytes());
269    stream.extend_from_slice(&self.n1v6_preamp_vcp[1].to_le_bytes());
270    stream.extend_from_slice(&self.n1v6_preamp_vcp[2].to_le_bytes());
271    stream.extend_from_slice(&self.p3v4f_ltb_vcp[0]  .to_le_bytes());
272    stream.extend_from_slice(&self.p3v4f_ltb_vcp[1]  .to_le_bytes());
273    stream.extend_from_slice(&self.p3v4f_ltb_vcp[2]  .to_le_bytes());
274    stream.extend_from_slice(&self.p3v4d_ltb_vcp[0]  .to_le_bytes());
275    stream.extend_from_slice(&self.p3v4d_ltb_vcp[1]  .to_le_bytes());
276    stream.extend_from_slice(&self.p3v4d_ltb_vcp[2]  .to_le_bytes());
277    stream.extend_from_slice(&self.p3v6_ltb_vcp[0]   .to_le_bytes());
278    stream.extend_from_slice(&self.p3v6_ltb_vcp[1]   .to_le_bytes());
279    stream.extend_from_slice(&self.p3v6_ltb_vcp[2]   .to_le_bytes());
280    stream.extend_from_slice(&self.n1v6_ltb_vcp[0]   .to_le_bytes());
281    stream.extend_from_slice(&self.n1v6_ltb_vcp[1]   .to_le_bytes());
282    stream.extend_from_slice(&self.n1v6_ltb_vcp[2]   .to_le_bytes());
283    stream.extend_from_slice(&self.pds_temp          .to_le_bytes());
284    stream.extend_from_slice(&self.pas_temp          .to_le_bytes());
285    stream.extend_from_slice(&self.nas_temp          .to_le_bytes());
286    stream.extend_from_slice(&self.shv_temp          .to_le_bytes());
287    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
288    stream
289  } 
290
291  fn from_bytestream(stream    : &Vec<u8>, 
292                     pos       : &mut usize) 
293    -> Result<PBMoniData, SerializationError>{
294    Self::verify_fixed(stream, pos)?;
295    let mut moni            = PBMoniData::new();
296    moni.board_id           = parse_u8(stream, pos) ; 
297    moni.p3v6_preamp_vcp[0] = parse_f32(stream, pos);
298    moni.p3v6_preamp_vcp[1] = parse_f32(stream, pos);
299    moni.p3v6_preamp_vcp[2] = parse_f32(stream, pos);
300    moni.n1v6_preamp_vcp[0] = parse_f32(stream, pos);
301    moni.n1v6_preamp_vcp[1] = parse_f32(stream, pos);
302    moni.n1v6_preamp_vcp[2] = parse_f32(stream, pos);
303    moni.p3v4f_ltb_vcp[0]   = parse_f32(stream, pos);
304    moni.p3v4f_ltb_vcp[1]   = parse_f32(stream, pos);
305    moni.p3v4f_ltb_vcp[2]   = parse_f32(stream, pos);
306    moni.p3v4d_ltb_vcp[0]   = parse_f32(stream, pos);
307    moni.p3v4d_ltb_vcp[1]   = parse_f32(stream, pos);
308    moni.p3v4d_ltb_vcp[2]   = parse_f32(stream, pos);
309    moni.p3v6_ltb_vcp[0]    = parse_f32(stream, pos);
310    moni.p3v6_ltb_vcp[1]    = parse_f32(stream, pos);
311    moni.p3v6_ltb_vcp[2]    = parse_f32(stream, pos);
312    moni.n1v6_ltb_vcp[0]    = parse_f32(stream, pos);
313    moni.n1v6_ltb_vcp[1]    = parse_f32(stream, pos);
314    moni.n1v6_ltb_vcp[2]    = parse_f32(stream, pos);
315    moni.pds_temp           = parse_f32(stream, pos);
316    moni.pas_temp           = parse_f32(stream, pos);
317    moni.nas_temp           = parse_f32(stream, pos);
318    moni.shv_temp           = parse_f32(stream, pos);
319    *pos += 2;// account for tail
320    Ok(moni)
321  }
322}
323
324#[cfg(feature = "random")]
325impl FromRandom for PBMoniData {
326    
327  fn from_random() -> PBMoniData {
328    let mut moni = Self::new();
329    let mut rng = rand::thread_rng();
330    moni.board_id           = rng.gen::<u8>(); 
331    for k in 0..3 {
332      let foo = rng.gen::<f32>();
333      moni.p3v6_preamp_vcp[k] = foo;
334    }
335    for k in 0..3 {
336      let foo = rng.gen::<f32>();
337      moni.n1v6_preamp_vcp[k] = foo;
338    }
339    for k in 0..3 {
340      let foo = rng.gen::<f32>();
341      moni.p3v4f_ltb_vcp[k] = foo;
342    }
343    for k in 0..3 {
344      let foo = rng.gen::<f32>();
345      moni.p3v4d_ltb_vcp[k] = foo;
346    }
347    for k in 0..3 {
348      let foo = rng.gen::<f32>();
349      moni.p3v6_ltb_vcp[k] = foo;
350    }
351    for k in 0..3 {
352      let foo = rng.gen::<f32>();
353      moni.n1v6_ltb_vcp[k] = foo;
354    }
355    moni.pds_temp = rng.gen::<f32>(); 
356    moni.pas_temp = rng.gen::<f32>(); 
357    moni.nas_temp = rng.gen::<f32>(); 
358    moni.shv_temp = rng.gen::<f32>(); 
359    moni
360  }
361}
362
363///////////////////////////////////////////////////////
364
365/// Preamp temperature and bias data
366#[derive(Debug, Copy, Clone, PartialEq)]
367pub struct PAMoniData {
368  pub board_id           : u8,
369  pub temps              : [f32;16],
370  pub biases             : [f32;16],
371  //#[cfg(feature = "polars")]
372  //pub mapped             : HashMap<String, f32>,
373}
374
375impl PAMoniData {
376
377  pub fn new() -> Self {
378    Self {
379      board_id  : 0,
380      temps     : [f32::MAX;16],
381      biases    : [f32::MAX;16],
382      //#[cfg(feature = "polars")]
383      //mapped    : HashMap::<String, f32>::new(),
384    }
385  }
386
387  #[cfg(feature = "tofcontrol")]
388  pub fn add_temps(&mut self, pt : &PATemp ) {
389    self.temps = pt.pa_temps;
390  }
391
392  #[cfg(feature = "tofcontrol")]
393  pub fn add_biases(&mut self, pb : &PAReadBias) {
394    self.biases = pb.read_biases;
395  }
396}
397
398impl Default for PAMoniData {
399  fn default() -> Self {
400    Self::new()
401  }
402}
403
404impl fmt::Display for PAMoniData {
405  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
406    write!(f, "<PAMoniData:
407  Board ID : {}
408  **16 Temp values**
409  T1   : {:.2} [\u{00B0}C]
410  T2   : {:.2} [\u{00B0}C]
411  T3   : {:.2} [\u{00B0}C]
412  T4   : {:.2} [\u{00B0}C]
413  T5   : {:.2} [\u{00B0}C]
414  T6   : {:.2} [\u{00B0}C]
415  T7   : {:.2} [\u{00B0}C]
416  T8   : {:.2} [\u{00B0}C]
417  T9   : {:.2} [\u{00B0}C]
418  T10  : {:.2} [\u{00B0}C]
419  T11  : {:.2} [\u{00B0}C]
420  T12  : {:.2} [\u{00B0}C]
421  T13  : {:.2} [\u{00B0}C]
422  T14  : {:.2} [\u{00B0}C]
423  T15  : {:.2} [\u{00B0}C]
424  T16  : {:.2} [\u{00B0}C]
425  **16 Bias voltages**
426  V1   : {:.3} [V]
427  V2   : {:.3} [V]
428  V3   : {:.3} [V]
429  V4   : {:.3} [V]
430  V5   : {:.3} [V]
431  V6   : {:.3} [V]
432  V7   : {:.3} [V]
433  V8   : {:.3} [V]
434  V9   : {:.3} [V]
435  V10  : {:.3} [V]
436  V11  : {:.3} [V]
437  V12  : {:.3} [V]
438  V13  : {:.3} [V]
439  V14  : {:.3} [V]
440  V15  : {:.3} [V]
441  V16  : {:.3} [V]>",
442  self.board_id,
443  if self.temps[0]  != f32::MAX {self.temps[0 ].to_string()} else {String::from("f32::MAX (ERR)")},
444  if self.temps[1]  != f32::MAX {self.temps[1 ].to_string()} else {String::from("f32::MAX (ERR)")},
445  if self.temps[2]  != f32::MAX {self.temps[2 ].to_string()} else {String::from("f32::MAX (ERR)")},
446  if self.temps[3]  != f32::MAX {self.temps[3 ].to_string()} else {String::from("f32::MAX (ERR)")},
447  if self.temps[4]  != f32::MAX {self.temps[4 ].to_string()} else {String::from("f32::MAX (ERR)")},
448  if self.temps[5]  != f32::MAX {self.temps[5 ].to_string()} else {String::from("f32::MAX (ERR)")},
449  if self.temps[6]  != f32::MAX {self.temps[6 ].to_string()} else {String::from("f32::MAX (ERR)")},
450  if self.temps[7]  != f32::MAX {self.temps[7 ].to_string()} else {String::from("f32::MAX (ERR)")},
451  if self.temps[8]  != f32::MAX {self.temps[8 ].to_string()} else {String::from("f32::MAX (ERR)")},
452  if self.temps[9]  != f32::MAX {self.temps[9 ].to_string()} else {String::from("f32::MAX (ERR)")},
453  if self.temps[10] != f32::MAX {self.temps[10].to_string()} else {String::from("f32::MAX (ERR)")},
454  if self.temps[11] != f32::MAX {self.temps[11].to_string()} else {String::from("f32::MAX (ERR)")},
455  if self.temps[12] != f32::MAX {self.temps[12].to_string()} else {String::from("f32::MAX (ERR)")},
456  if self.temps[13] != f32::MAX {self.temps[13].to_string()} else {String::from("f32::MAX (ERR)")},
457  if self.temps[14] != f32::MAX {self.temps[14].to_string()} else {String::from("f32::MAX (ERR)")},
458  if self.temps[15] != f32::MAX {self.temps[15].to_string()} else {String::from("f32::MAX (ERR)")},
459  self.biases[0],
460  self.biases[1],
461  self.biases[2],
462  self.biases[3],
463  self.biases[4],
464  self.biases[5],
465  self.biases[6],
466  self.biases[7],
467  self.biases[8],
468  self.biases[9],
469  self.biases[10],
470  self.biases[11],
471  self.biases[12],
472  self.biases[13],
473  self.biases[14],
474  self.biases[15])
475  }
476}
477
478impl Packable for PAMoniData {
479  const PACKET_TYPE : PacketType = PacketType::PAMoniData;
480}
481
482impl Serialization for PAMoniData {
483  
484  const HEAD : u16 = 0xAAAA;
485  const TAIL : u16 = 0x5555;
486  /// The data size when serialized to a bytestream
487  /// This needs to be updated when we change the 
488  /// packet layout, e.g. add new members.
489  /// HEAD + TAIL + sum(sizeof(m) for m in _all_members_))
490  const SIZE : usize  = 4 + 1 + (4*16*2);
491  
492  fn to_bytestream(&self) -> Vec<u8> {
493    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
494    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
495    stream.extend_from_slice(&self.board_id.to_le_bytes()); 
496    for k in 0..16 {
497      stream.extend_from_slice(&self.temps[k].to_le_bytes());
498    }
499    for k in 0..16 {
500      stream.extend_from_slice(&self.biases[k].to_le_bytes());
501    }
502    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
503    stream
504  }
505  
506  fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
507    -> Result<Self, SerializationError> {
508    let mut moni_data      = Self::new();
509    Self::verify_fixed(stream, pos)?;
510    moni_data.board_id = parse_u8(stream, pos);
511    for k in 0..16 {
512      moni_data.temps[k] = parse_f32(stream, pos);
513    }
514    for k in 0..16 {
515      moni_data.biases[k] = parse_f32(stream, pos);
516    }
517    *pos += 2;
518    Ok(moni_data)
519  }
520}
521
522impl MoniData for PAMoniData {
523  
524  fn get_board_id(&self) -> u8 {
525    return self.board_id;
526  }
527
528  fn keys() -> Vec<&'static str> {
529    vec!["board_id",
530         "temps1"  , "temps2"  , "temps3"  , "temps4"  ,
531         "temps5"  , "temps6"  , "temps7"  , "temps8"  , 
532         "temps9"  , "temps10" , "temps11" , "temps12" ,
533         "temps13" , "temps14" , "temps15" , "temps16" ,
534         "biases1" , "biases2" , "biases3" , "biases4" , 
535         "biases5" , "biases6" , "biases7" , "biases8" ,
536         "biases9" , "biases10", "biases11", "biases12",
537         "biases13", "biases14", "biases15", "biases16" ]
538  }
539
540  fn get(&self, varname : &str) -> Option<f32> {
541    match varname {
542      "board_id" =>  Some(self.board_id as f32),
543      "temps1"   =>  Some(self.temps[0]  ),
544      "temps2"   =>  Some(self.temps[1]  ),
545      "temps3"   =>  Some(self.temps[2]  ),
546      "temps4"   =>  Some(self.temps[3]  ),
547      "temps5"   =>  Some(self.temps[4]  ),
548      "temps6"   =>  Some(self.temps[5]  ),
549      "temps7"   =>  Some(self.temps[6]  ),
550      "temps8"   =>  Some(self.temps[7]  ),
551      "temps9"   =>  Some(self.temps[8]  ),
552      "temps10"  =>  Some(self.temps[9]  ),
553      "temps11"  =>  Some(self.temps[10] ),
554      "temps12"  =>  Some(self.temps[11] ),
555      "temps13"  =>  Some(self.temps[12] ),
556      "temps14"  =>  Some(self.temps[13] ),
557      "temps15"  =>  Some(self.temps[14] ),
558      "temps16"  =>  Some(self.temps[15] ),
559      "biases1"  =>  Some(self.biases[0] ),
560      "biases2"  =>  Some(self.biases[1] ),
561      "biases3"  =>  Some(self.biases[2] ),
562      "biases4"  =>  Some(self.biases[3] ),
563      "biases5"  =>  Some(self.biases[4] ),
564      "biases6"  =>  Some(self.biases[5] ),
565      "biases7"  =>  Some(self.biases[6] ),
566      "biases8"  =>  Some(self.biases[7] ),
567      "biases9"  =>  Some(self.biases[8] ),
568      "biases10" =>  Some(self.biases[9] ),
569      "biases11" =>  Some(self.biases[10]),
570      "biases12" =>  Some(self.biases[11]),
571      "biases13" =>  Some(self.biases[12]),
572      "biases14" =>  Some(self.biases[13]),
573      "biases15" =>  Some(self.biases[14]),
574      "biases16" =>  Some(self.biases[15]),
575      _          =>  None
576    }
577  }
578  
579}
580
581#[cfg(feature = "random")]
582impl FromRandom for PAMoniData {
583    
584  fn from_random() -> Self {
585    let mut moni = Self::new();
586    let mut rng = rand::thread_rng();
587    moni.board_id     = rng.gen::<u8>(); 
588    for k in 0..16 {
589      moni.temps[k]   = rng.gen::<f32>(); 
590    }
591    for k in 0..16 {
592      moni.biases[k]  = rng.gen::<f32>(); 
593    }
594    moni
595  }
596}
597
598///////////////////////////////////////////////////////
599
600/// Sensors on the LTB
601#[derive(Debug, Copy, Clone, PartialEq)]
602pub struct LTBMoniData {
603  pub board_id   : u8,
604  pub trenz_temp : f32,
605  pub ltb_temp   : f32,
606  pub thresh     : [f32;3],
607}
608
609impl LTBMoniData {
610  pub fn new() -> LTBMoniData {
611    LTBMoniData {
612      board_id   : 0,
613      trenz_temp : f32::MAX,
614      ltb_temp   : f32::MAX,
615      thresh     : [f32::MAX,f32::MAX,f32::MAX],
616    }
617  }
618
619  #[cfg(feature = "tofcontrol")]
620  pub fn add_temps(&mut self, lt : &LTBTemp) {
621    self.trenz_temp = lt.trenz_temp;
622    self.ltb_temp   = lt.board_temp;
623  }
624
625  #[cfg(feature = "tofcontrol")]
626  pub fn add_thresh(&mut self, lt : &LTBThreshold) {
627    self.thresh = [lt.thresh_0, lt.thresh_1, lt.thresh_2];
628  }
629}
630
631impl Default for LTBMoniData {
632  fn default() -> Self {
633    Self::new()
634  }
635}
636
637impl fmt::Display for LTBMoniData {
638  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
639    write!(f, "<LTBMoniData:
640  Board ID  : {}
641  ** Temperatures **
642  TRENZ TMP : {:.2} [\u{00B0}C]
643  LTB   TMP : {:.2} [\u{00B0}C]
644  ** Threshold Voltages **
645  THR HIT, THR BETA, THR VETO : {:.3} | {:.3} | {:.3} [mV]>",
646  self.board_id,
647  self.trenz_temp,
648  self.ltb_temp,
649  self.thresh[0],
650  self.thresh[1],
651  self.thresh[2])
652  }
653}
654
655
656impl Packable for LTBMoniData {
657  const PACKET_TYPE : PacketType = PacketType::LTBMoniData;
658}
659
660impl Serialization for LTBMoniData {
661  
662  const HEAD : u16 = 0xAAAA;
663  const TAIL : u16 = 0x5555;
664  /// The data size when serialized to a bytestream
665  /// This needs to be updated when we change the 
666  /// packet layout, e.g. add new members.
667  /// HEAD + TAIL + sum(sizeof(m) for m in _all_members_))
668  const SIZE : usize  = 4 + 1 + (4*5) ;
669  
670  fn to_bytestream(&self) -> Vec<u8> {
671    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
672    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
673    stream.extend_from_slice(&self.board_id          .to_le_bytes()); 
674    stream.extend_from_slice(&self.trenz_temp. to_le_bytes());
675    stream.extend_from_slice(&self.ltb_temp.   to_le_bytes());
676    for k in 0..3 {
677      stream.extend_from_slice(&self.thresh[k].to_le_bytes());
678    }
679    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
680    stream
681  }
682  
683  fn from_bytestream(stream    : &Vec<u8>, 
684                     pos       : &mut usize) 
685    -> Result<Self, SerializationError>{
686    let mut moni     = Self::new();
687    Self::verify_fixed(stream, pos)?;
688    moni.board_id    = parse_u8(stream, pos);
689    moni.trenz_temp  = parse_f32(stream, pos);
690    moni.ltb_temp    = parse_f32(stream, pos);
691    for k in 0..3 {
692      moni.thresh[k] = parse_f32(stream, pos);
693    }
694    *pos += 2;
695    Ok(moni)
696  }
697}
698
699#[cfg(feature = "random")]
700impl FromRandom for LTBMoniData {
701    
702  fn from_random() -> LTBMoniData {
703    let mut moni  = Self::new();
704    let mut rng   = rand::thread_rng();
705    moni.board_id = rng.gen::<u8>(); 
706    moni.trenz_temp = rng.gen::<f32>();
707    moni.ltb_temp   = rng.gen::<f32>();
708    for k in 0..3 {
709      moni.thresh[k] = rng.gen::<f32>();
710    }
711    moni
712  }
713}
714
715impl MoniData for LTBMoniData {
716  fn get_board_id(&self) -> u8 {
717    self.board_id
718  }
719  
720  /// Access the (data) members by name 
721  fn get(&self, varname : &str) -> Option<f32> {
722    match varname {
723    "board_id"    => Some(self.board_id as f32),
724    "trenz_temp"  => Some(self.trenz_temp),
725    "ltb_temp"    => Some(self.ltb_temp),
726    "thresh0"     => Some(self.thresh[0]),
727    "thresh1"     => Some(self.thresh[1]),
728    "thresh2"     => Some(self.thresh[2]),
729    _             => None
730    }
731  }
732
733  /// A list of the variables in this MoniData
734  fn keys() -> Vec<&'static str> {
735    vec!["board_id", "trenz_temp", "ltb_temp",
736         "thresh0", "thresh1", "thresh2"]
737  }
738}
739
740///////////////////////////////////////////////////////
741
742
743/// Sensors on the individual RB
744///  
745/// This includes temperatures, power data,
746/// pressure, humidity
747/// as well as the magnetic sensors
748#[derive(Debug, Copy, Clone, PartialEq)]
749pub struct RBMoniData {
750  pub board_id           : u8,
751  pub rate               : u16,
752  pub tmp_drs            : f32,
753  pub tmp_clk            : f32,
754  pub tmp_adc            : f32,
755  pub tmp_zynq           : f32,
756  pub tmp_lis3mdltr      : f32,
757  pub tmp_bm280          : f32,
758  pub pressure           : f32,
759  pub humidity           : f32,
760  pub mag_x              : f32,
761  pub mag_y              : f32,
762  pub mag_z              : f32,
763  pub drs_dvdd_voltage   : f32, 
764  pub drs_dvdd_current   : f32,
765  pub drs_dvdd_power     : f32,
766  pub p3v3_voltage       : f32,
767  pub p3v3_current       : f32,
768  pub p3v3_power         : f32,
769  pub zynq_voltage       : f32,
770  pub zynq_current       : f32,
771  pub zynq_power         : f32,
772  pub p3v5_voltage       : f32, 
773  pub p3v5_current       : f32,
774  pub p3v5_power         : f32,
775  pub adc_dvdd_voltage   : f32,
776  pub adc_dvdd_current   : f32,
777  pub adc_dvdd_power     : f32,
778  pub adc_avdd_voltage   : f32,
779  pub adc_avdd_current   : f32,
780  pub adc_avdd_power     : f32,
781  pub drs_avdd_voltage   : f32, 
782  pub drs_avdd_current   : f32,
783  pub drs_avdd_power     : f32,
784  pub n1v5_voltage       : f32,
785  pub n1v5_current       : f32,
786  pub n1v5_power         : f32,
787}
788
789impl RBMoniData {
790
791  #[cfg(feature = "tofcontrol")]
792  pub fn add_rbtemp(&mut self, rb_temp : &RBTemp) {
793    self.tmp_drs         = rb_temp.drs_temp      ; 
794    self.tmp_clk         = rb_temp.clk_temp      ; 
795    self.tmp_adc         = rb_temp.adc_temp      ; 
796    self.tmp_zynq        = rb_temp.zynq_temp     ; 
797    self.tmp_lis3mdltr   = rb_temp.lis3mdltr_temp; 
798    self.tmp_bm280       = rb_temp.bme280_temp   ; 
799  }
800
801  #[cfg(feature = "tofcontrol")] 
802  pub fn add_rbmag(&mut self, rb_mag   : &RBMag) {
803    self.mag_x   = rb_mag.mag_xyz[0];
804    self.mag_y   = rb_mag.mag_xyz[1];
805    self.mag_z   = rb_mag.mag_xyz[2];
806  }
807 
808  pub fn get_mag_tot(&self) -> f32 {
809    (self.mag_x.powi(2) + self.mag_y.powi(2) + self.mag_z.powi(2)).sqrt()
810  }
811
812
813  #[cfg(feature = "tofcontrol")]
814  pub fn add_rbvcp(&mut self, rb_vcp   : &RBVcp) {
815    self.drs_dvdd_voltage = rb_vcp.drs_dvdd_vcp[0] ;
816    self.drs_dvdd_current = rb_vcp.drs_dvdd_vcp[1] ;
817    self.drs_dvdd_power   = rb_vcp.drs_dvdd_vcp[2] ;
818    self.p3v3_voltage     = rb_vcp.p3v3_vcp[0]  ;
819    self.p3v3_current     = rb_vcp.p3v3_vcp[1]  ;
820    self.p3v3_power       = rb_vcp.p3v3_vcp[2]  ;
821    self.zynq_voltage     = rb_vcp.zynq_vcp[0]  ;
822    self.zynq_current     = rb_vcp.zynq_vcp[1]  ;
823    self.zynq_power       = rb_vcp.zynq_vcp[2]  ;
824    self.p3v5_voltage     = rb_vcp.p3v5_vcp[0]  ;
825    self.p3v5_current     = rb_vcp.p3v5_vcp[1]  ;
826    self.p3v5_power       = rb_vcp.p3v5_vcp[2]  ;
827    self.adc_dvdd_voltage = rb_vcp.adc_dvdd_vcp[0] ;
828    self.adc_dvdd_current = rb_vcp.adc_dvdd_vcp[1] ;
829    self.adc_dvdd_power   = rb_vcp.adc_dvdd_vcp[2] ;
830    self.adc_avdd_voltage = rb_vcp.adc_avdd_vcp[0]  ;
831    self.adc_avdd_current = rb_vcp.adc_avdd_vcp[1]  ;
832    self.adc_avdd_power   = rb_vcp.adc_avdd_vcp[2]  ;
833    self.drs_avdd_voltage = rb_vcp.drs_avdd_vcp[0]  ;
834    self.drs_avdd_current = rb_vcp.drs_avdd_vcp[1]  ;
835    self.drs_avdd_power   = rb_vcp.drs_avdd_vcp[2]  ;
836    self.n1v5_voltage     = rb_vcp.n1v5_vcp[0]      ;
837    self.n1v5_current     = rb_vcp.n1v5_vcp[1]      ;
838    self.n1v5_power       = rb_vcp.n1v5_vcp[2]      ;
839  }
840  
841  #[cfg(feature = "tofcontrol")] 
842  pub fn add_rbph(&mut self, rb_ph   : &RBPh) {
843    self.pressure = rb_ph.pressure;
844    self.humidity = rb_ph.humidity;
845  }
846
847  pub fn new() -> Self {
848    Self {
849      board_id           : 0, 
850      rate               : 0,
851      tmp_drs            : f32::MAX,
852      tmp_clk            : f32::MAX,
853      tmp_adc            : f32::MAX,
854      tmp_zynq           : f32::MAX,
855      tmp_lis3mdltr      : f32::MAX,
856      tmp_bm280          : f32::MAX,
857      pressure           : f32::MAX,
858      humidity           : f32::MAX,
859      mag_x              : f32::MAX,
860      mag_y              : f32::MAX,
861      mag_z              : f32::MAX,
862      drs_dvdd_voltage   : f32::MAX, 
863      drs_dvdd_current   : f32::MAX,
864      drs_dvdd_power     : f32::MAX,
865      p3v3_voltage       : f32::MAX,
866      p3v3_current       : f32::MAX,
867      p3v3_power         : f32::MAX,
868      zynq_voltage       : f32::MAX,
869      zynq_current       : f32::MAX,
870      zynq_power         : f32::MAX,
871      p3v5_voltage       : f32::MAX, 
872      p3v5_current       : f32::MAX,
873      p3v5_power         : f32::MAX,
874      adc_dvdd_voltage   : f32::MAX,
875      adc_dvdd_current   : f32::MAX,
876      adc_dvdd_power     : f32::MAX,
877      adc_avdd_voltage   : f32::MAX,
878      adc_avdd_current   : f32::MAX,
879      adc_avdd_power     : f32::MAX,
880      drs_avdd_voltage   : f32::MAX, 
881      drs_avdd_current   : f32::MAX,
882      drs_avdd_power     : f32::MAX,
883      n1v5_voltage       : f32::MAX,
884      n1v5_current       : f32::MAX,
885      n1v5_power         : f32::MAX,
886    }
887  }
888}
889
890impl Default for RBMoniData {
891  fn default() -> Self {
892    Self::new()
893  }
894}
895
896impl fmt::Display for RBMoniData {
897  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
898    write!(f, "<RBMoniData:
899  BOARD ID       {}
900  RATE           {}    [Hz] 
901  ** Temperatures **
902  DRS TMP        {:.3} [\u{00B0}C]
903  CLK TMP        {:.3} [\u{00B0}C]
904  ADC TMP        {:.3} [\u{00B0}C]
905  ZYNQ TMP       {:.3} [\u{00B0}C]
906  LIS3MDLTR TMP  {:.3} [\u{00B0}C]  
907  BM280 TMP      {:.3} [\u{00B0}C]
908  ** Ambience **
909  PRESSURE       {:.3} [hPa]
910  HUMIDITY       {:.3} [%]
911  MAG_X , MAG_Y, MAG_Z, MAG_TOT:
912   |->  {:.3} [G] | {:.3} [G] | {:.3} [G] | {:.3} [G]
913  ** Power **
914  ZYNQ 3.3V         Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]
915  3.3V              Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]
916  3.5V              Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]
917  -1.5V             Power: {:.3}  [V] | {:.3} [A] | {:.3} [W]
918  DRS4 Digital 2.5V Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]
919  DRS4 Analog 2.5V  Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]
920  ADC Digital 2.5V  Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]
921  ADC Analog 3.0V   Power:  {:.3}  [V] | {:.3} [A] | {:.3} [W]>",
922           self.board_id        , 
923           self.rate            ,
924           self.tmp_drs         ,
925           self.tmp_clk         ,
926           self.tmp_adc         ,
927           self.tmp_zynq        ,
928           self.tmp_lis3mdltr   ,
929           self.tmp_bm280       ,
930           self.pressure        ,
931           self.humidity        ,
932           self.mag_x           ,
933           self.mag_y           ,
934           self.mag_z           ,
935           self.get_mag_tot()   ,
936           self.zynq_voltage    ,
937           self.zynq_current    ,
938           self.zynq_power      ,
939           self.p3v3_voltage    ,
940           self.p3v3_current    ,
941           self.p3v3_power      ,
942           self.p3v5_voltage    , 
943           self.p3v5_current    ,
944           self.p3v5_power      ,
945           self.n1v5_voltage    ,
946           self.n1v5_current    ,
947           self.n1v5_power      ,
948           self.drs_dvdd_voltage, 
949           self.drs_dvdd_current,
950           self.drs_dvdd_power  ,
951           self.drs_avdd_voltage, 
952           self.drs_avdd_current,
953           self.drs_avdd_power  ,
954           self.adc_dvdd_voltage,
955           self.adc_dvdd_current,
956           self.adc_dvdd_power  ,
957           self.adc_avdd_voltage,
958           self.adc_avdd_current,
959           self.adc_avdd_power  )
960  }
961}
962
963impl MoniData for RBMoniData {
964
965  fn get_board_id(&self) -> u8 {
966    self.board_id
967  }
968  
969  /// Access the (data) members by name 
970  fn get(&self, varname : &str) -> Option<f32> {
971    match varname {
972      "board_id"         => Some(self.board_id as   f32),
973      "rate"             => Some(self.rate as f32      ), 
974      "tmp_drs"          => Some(self.tmp_drs          ), 
975      "tmp_clk"          => Some(self.tmp_clk          ), 
976      "tmp_adc"          => Some(self.tmp_adc          ), 
977      "tmp_zynq"         => Some(self.tmp_zynq         ), 
978      "tmp_lis3mdltr"    => Some(self.tmp_lis3mdltr    ), 
979      "tmp_bm280"        => Some(self.tmp_bm280        ), 
980      "pressure"         => Some(self.pressure         ), 
981      "humidity"         => Some(self.humidity         ), 
982      "mag_x"            => Some(self.mag_x            ), 
983      "mag_y"            => Some(self.mag_y            ), 
984      "mag_z"            => Some(self.mag_z            ), 
985      "mag_tot"          => Some(self.get_mag_tot()    ),
986      "drs_dvdd_voltage" => Some(self.drs_dvdd_voltage ), 
987      "drs_dvdd_current" => Some(self.drs_dvdd_current ), 
988      "drs_dvdd_power"   => Some(self.drs_dvdd_power   ), 
989      "p3v3_voltage"     => Some(self.p3v3_voltage     ), 
990      "p3v3_current"     => Some(self.p3v3_current     ), 
991      "p3v3_power"       => Some(self.p3v3_power       ), 
992      "zynq_voltage"     => Some(self.zynq_voltage     ), 
993      "zynq_current"     => Some(self.zynq_current     ), 
994      "zynq_power"       => Some(self.zynq_power       ), 
995      "p3v5_voltage"     => Some(self.p3v5_voltage     ), 
996      "p3v5_current"     => Some(self.p3v5_current     ), 
997      "p3v5_power"       => Some(self.p3v5_power       ), 
998      "adc_dvdd_voltage" => Some(self.adc_dvdd_voltage ), 
999      "adc_dvdd_current" => Some(self.adc_dvdd_current ), 
1000      "adc_dvdd_power"   => Some(self.adc_dvdd_power   ), 
1001      "adc_avdd_voltage" => Some(self.adc_avdd_voltage ), 
1002      "adc_avdd_current" => Some(self.adc_avdd_current ), 
1003      "adc_avdd_power"   => Some(self.adc_avdd_power   ), 
1004      "drs_avdd_voltage" => Some(self.drs_avdd_voltage ), 
1005      "drs_avdd_current" => Some(self.drs_avdd_current ), 
1006      "drs_avdd_power"   => Some(self.drs_avdd_power   ), 
1007      "n1v5_voltage"     => Some(self.n1v5_voltage     ), 
1008      "n1v5_current"     => Some(self.n1v5_current     ), 
1009      "n1v5_power"       => Some(self.n1v5_power       ), 
1010      _             => None
1011    }
1012  }
1013
1014  /// A list of the variables in this MoniData
1015  fn keys() -> Vec<&'static str> {
1016    vec![
1017      "board_id"        , 
1018      "rate"            , 
1019      "tmp_drs"         , 
1020      "tmp_clk"         , 
1021      "tmp_adc"         , 
1022      "tmp_zynq"        , 
1023      "tmp_lis3mdltr"   , 
1024      "tmp_bm280"       , 
1025      "pressure"        , 
1026      "humidity"        , 
1027      "mag_x"           , 
1028      "mag_y"           , 
1029      "mag_z"           , 
1030      "drs_dvdd_voltage", 
1031      "drs_dvdd_current", 
1032      "drs_dvdd_power"  , 
1033      "p3v3_voltage"    , 
1034      "p3v3_current"    , 
1035      "p3v3_power"      , 
1036      "zynq_voltage"    , 
1037      "zynq_current"    , 
1038      "zynq_power"      , 
1039      "p3v5_voltage"    , 
1040      "p3v5_current"    , 
1041      "p3v5_power"      , 
1042      "adc_dvdd_voltage", 
1043      "adc_dvdd_current", 
1044      "adc_dvdd_power"  , 
1045      "adc_avdd_voltage", 
1046      "adc_avdd_current", 
1047      "adc_avdd_power"  , 
1048      "drs_avdd_voltage", 
1049      "drs_avdd_current", 
1050      "drs_avdd_power"  , 
1051      "n1v5_voltage"    , 
1052      "n1v5_current"    , 
1053      "n1v5_power"      ] 
1054  }
1055}
1056
1057impl Packable for RBMoniData {
1058  const PACKET_TYPE : PacketType = PacketType::RBMoniData;
1059}
1060
1061impl Serialization for RBMoniData {
1062  
1063  const HEAD : u16 = 0xAAAA;
1064  const TAIL : u16 = 0x5555;
1065  /// The data size when serialized to a bytestream
1066  /// This needs to be updated when we change the 
1067  /// packet layout, e.g. add new members.
1068  /// HEAD + TAIL + sum(sizeof(m) for m in _all_members_))
1069  const SIZE : usize  = 7 + (36*4) ;
1070  
1071  fn to_bytestream(&self) -> Vec<u8> {
1072    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
1073    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
1074    stream.extend_from_slice(&self.board_id          .to_le_bytes()); 
1075    stream.extend_from_slice(&self.rate              .to_le_bytes()); 
1076    stream.extend_from_slice(&self.tmp_drs           .to_le_bytes()); 
1077    stream.extend_from_slice(&self.tmp_clk           .to_le_bytes()); 
1078    stream.extend_from_slice(&self.tmp_adc           .to_le_bytes()); 
1079    stream.extend_from_slice(&self.tmp_zynq          .to_le_bytes()); 
1080    stream.extend_from_slice(&self.tmp_lis3mdltr     .to_le_bytes()); 
1081    stream.extend_from_slice(&self.tmp_bm280         .to_le_bytes()); 
1082    stream.extend_from_slice(&self.pressure          .to_le_bytes()); 
1083    stream.extend_from_slice(&self.humidity          .to_le_bytes()); 
1084    stream.extend_from_slice(&self.mag_x             .to_le_bytes()); 
1085    stream.extend_from_slice(&self.mag_y             .to_le_bytes()); 
1086    stream.extend_from_slice(&self.mag_z             .to_le_bytes());
1087    // padding - just for compatibility
1088    stream.extend_from_slice(&0.0_f32                 .to_le_bytes());
1089    stream.extend_from_slice(&self.drs_dvdd_voltage   .to_le_bytes()); 
1090    stream.extend_from_slice(&self.drs_dvdd_current   .to_le_bytes()); 
1091    stream.extend_from_slice(&self.drs_dvdd_power     .to_le_bytes()); 
1092    stream.extend_from_slice(&self.p3v3_voltage       .to_le_bytes()); 
1093    stream.extend_from_slice(&self.p3v3_current       .to_le_bytes()); 
1094    stream.extend_from_slice(&self.p3v3_power         .to_le_bytes()); 
1095    stream.extend_from_slice(&self.zynq_voltage       .to_le_bytes()); 
1096    stream.extend_from_slice(&self.zynq_current       .to_le_bytes()); 
1097    stream.extend_from_slice(&self.zynq_power         .to_le_bytes()); 
1098    stream.extend_from_slice(&self.p3v5_voltage       .to_le_bytes()); 
1099    stream.extend_from_slice(&self.p3v5_current       .to_le_bytes()); 
1100    stream.extend_from_slice(&self.p3v5_power         .to_le_bytes()); 
1101    stream.extend_from_slice(&self.adc_dvdd_voltage   .to_le_bytes()); 
1102    stream.extend_from_slice(&self.adc_dvdd_current   .to_le_bytes()); 
1103    stream.extend_from_slice(&self.adc_dvdd_power     .to_le_bytes()); 
1104    stream.extend_from_slice(&self.adc_avdd_voltage   .to_le_bytes()); 
1105    stream.extend_from_slice(&self.adc_avdd_current   .to_le_bytes()); 
1106    stream.extend_from_slice(&self.adc_avdd_power     .to_le_bytes()); 
1107    stream.extend_from_slice(&self.drs_avdd_voltage   .to_le_bytes()); 
1108    stream.extend_from_slice(&self.drs_avdd_current   .to_le_bytes()); 
1109    stream.extend_from_slice(&self.drs_avdd_power     .to_le_bytes()); 
1110    stream.extend_from_slice(&self.n1v5_voltage       .to_le_bytes()); 
1111    stream.extend_from_slice(&self.n1v5_current       .to_le_bytes()); 
1112    stream.extend_from_slice(&self.n1v5_power         .to_le_bytes()); 
1113    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
1114    stream
1115  }
1116
1117  fn from_bytestream(stream    : &Vec<u8>, 
1118                     pos       : &mut usize) 
1119    -> Result<RBMoniData, SerializationError>{
1120    let mut moni_data = Self::new();
1121    Self::verify_fixed(stream, pos)?;
1122    moni_data.board_id           = parse_u8( stream, pos); 
1123    moni_data.rate               = parse_u16(stream, pos); 
1124    moni_data.tmp_drs            = parse_f32(stream, pos); 
1125    moni_data.tmp_clk            = parse_f32(stream, pos); 
1126    moni_data.tmp_adc            = parse_f32(stream, pos); 
1127    moni_data.tmp_zynq           = parse_f32(stream, pos); 
1128    moni_data.tmp_lis3mdltr      = parse_f32(stream, pos); 
1129    moni_data.tmp_bm280          = parse_f32(stream, pos); 
1130    moni_data.pressure           = parse_f32(stream, pos); 
1131    moni_data.humidity           = parse_f32(stream, pos); 
1132    moni_data.mag_x              = parse_f32(stream, pos); 
1133    moni_data.mag_y              = parse_f32(stream, pos); 
1134    moni_data.mag_z              = parse_f32(stream, pos); 
1135    // compatibility, no mag_tot anymore
1136    *pos += 4;
1137    moni_data.drs_dvdd_voltage   = parse_f32(stream, pos); 
1138    moni_data.drs_dvdd_current   = parse_f32(stream, pos); 
1139    moni_data.drs_dvdd_power     = parse_f32(stream, pos); 
1140    moni_data.p3v3_voltage       = parse_f32(stream, pos); 
1141    moni_data.p3v3_current       = parse_f32(stream, pos); 
1142    moni_data.p3v3_power         = parse_f32(stream, pos); 
1143    moni_data.zynq_voltage       = parse_f32(stream, pos); 
1144    moni_data.zynq_current       = parse_f32(stream, pos); 
1145    moni_data.zynq_power         = parse_f32(stream, pos); 
1146    moni_data.p3v5_voltage       = parse_f32(stream, pos); 
1147    moni_data.p3v5_current       = parse_f32(stream, pos); 
1148    moni_data.p3v5_power         = parse_f32(stream, pos); 
1149    moni_data.adc_dvdd_voltage   = parse_f32(stream, pos); 
1150    moni_data.adc_dvdd_current   = parse_f32(stream, pos); 
1151    moni_data.adc_dvdd_power     = parse_f32(stream, pos); 
1152    moni_data.adc_avdd_voltage   = parse_f32(stream, pos); 
1153    moni_data.adc_avdd_current   = parse_f32(stream, pos); 
1154    moni_data.adc_avdd_power     = parse_f32(stream, pos); 
1155    moni_data.drs_avdd_voltage   = parse_f32(stream, pos); 
1156    moni_data.drs_avdd_current   = parse_f32(stream, pos); 
1157    moni_data.drs_avdd_power     = parse_f32(stream, pos); 
1158    moni_data.n1v5_voltage       = parse_f32(stream, pos); 
1159    moni_data.n1v5_current       = parse_f32(stream, pos); 
1160    moni_data.n1v5_power         = parse_f32(stream, pos); 
1161    *pos += 2; // for tail
1162    Ok(moni_data) 
1163  }
1164}
1165
1166#[cfg(feature = "random")]
1167impl FromRandom for RBMoniData {
1168    
1169  fn from_random() -> RBMoniData {
1170    let mut moni = RBMoniData::new();
1171    let mut rng = rand::thread_rng();
1172    moni.board_id           = rng.gen::<u8>(); 
1173    moni.rate               = rng.gen::<u16>();
1174    moni.tmp_drs            = rng.gen::<f32>();
1175    moni.tmp_clk            = rng.gen::<f32>();
1176    moni.tmp_adc            = rng.gen::<f32>();
1177    moni.tmp_zynq           = rng.gen::<f32>();
1178    moni.tmp_lis3mdltr      = rng.gen::<f32>();
1179    moni.tmp_bm280          = rng.gen::<f32>();
1180    moni.pressure           = rng.gen::<f32>();
1181    moni.humidity           = rng.gen::<f32>();
1182    moni.mag_x              = rng.gen::<f32>();
1183    moni.mag_y              = rng.gen::<f32>();
1184    moni.mag_z              = rng.gen::<f32>();
1185    moni.drs_dvdd_voltage   = rng.gen::<f32>(); 
1186    moni.drs_dvdd_current   = rng.gen::<f32>();
1187    moni.drs_dvdd_power     = rng.gen::<f32>();
1188    moni.p3v3_voltage       = rng.gen::<f32>();
1189    moni.p3v3_current       = rng.gen::<f32>();
1190    moni.p3v3_power         = rng.gen::<f32>();
1191    moni.zynq_voltage       = rng.gen::<f32>();
1192    moni.zynq_current       = rng.gen::<f32>();
1193    moni.zynq_power         = rng.gen::<f32>();
1194    moni.p3v5_voltage       = rng.gen::<f32>(); 
1195    moni.p3v5_current       = rng.gen::<f32>();
1196    moni.p3v5_power         = rng.gen::<f32>();
1197    moni.adc_dvdd_voltage   = rng.gen::<f32>();
1198    moni.adc_dvdd_current   = rng.gen::<f32>();
1199    moni.adc_dvdd_power     = rng.gen::<f32>();
1200    moni.adc_avdd_voltage   = rng.gen::<f32>();
1201    moni.adc_avdd_current   = rng.gen::<f32>();
1202    moni.adc_avdd_power     = rng.gen::<f32>();
1203    moni.drs_avdd_voltage   = rng.gen::<f32>(); 
1204    moni.drs_avdd_current   = rng.gen::<f32>();
1205    moni.drs_avdd_power     = rng.gen::<f32>();
1206    moni.n1v5_voltage       = rng.gen::<f32>();
1207    moni.n1v5_current       = rng.gen::<f32>();
1208    moni.n1v5_power         = rng.gen::<f32>();
1209    moni
1210  }
1211}
1212
1213
1214///////////////////////////////////////////////////////
1215
1216#[derive(Debug, Copy, Clone, PartialEq)]
1217pub struct CPUMoniData {
1218  pub uptime     : u32,
1219  pub disk_usage : u8,
1220  pub cpu_freq   : [u32; 4],
1221  pub cpu_temp   : f32,
1222  pub cpu0_temp  : f32,
1223  pub cpu1_temp  : f32,
1224  pub mb_temp    : f32,
1225}
1226
1227impl CPUMoniData {
1228  pub fn new() -> Self {
1229    Self {
1230      uptime     : u32::MAX,
1231      disk_usage : u8::MAX,
1232      cpu_freq   : [u32::MAX; 4],
1233      cpu_temp   : f32::MAX,
1234      cpu0_temp  : f32::MAX,
1235      cpu1_temp  : f32::MAX,
1236      mb_temp    : f32::MAX,
1237    }
1238  }
1239
1240  pub fn get_temps(&self) -> Vec<f32> {
1241    vec![self.cpu0_temp, self.cpu1_temp, self.cpu_temp, self.mb_temp]
1242  }
1243
1244  #[cfg(feature = "tofcontrol")]
1245  pub fn add_temps(&mut self, cpu_temps : &CPUTempDebug) {
1246    self.cpu_temp   = cpu_temps.cpu_temp;
1247    self.cpu0_temp  = cpu_temps.cpu0_temp;
1248    self.cpu1_temp  = cpu_temps.cpu1_temp;
1249    self.mb_temp    = cpu_temps.mb_temp;
1250  }
1251
1252  #[cfg(feature = "tofcontrol")]
1253  pub fn add_info(&mut self, cpu_info : &CPUInfoDebug) {
1254    self.uptime = cpu_info.uptime;
1255    self.disk_usage = cpu_info.disk_usage;
1256    self.cpu_freq   = cpu_info.cpu_freq;
1257  }
1258}
1259
1260impl Default for CPUMoniData {
1261  fn default() -> Self {
1262    Self::new()
1263  }
1264}
1265
1266impl fmt::Display for CPUMoniData {
1267  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1268    write!(f, "<CPUMoniData:
1269  core0   temp [\u{00B0}C] : {:.2} 
1270  core1   temp [\u{00B0}C] : {:.2} 
1271  CPU     temp [\u{00B0}C] : {:.2} 
1272  MB      temp [\u{00B0}C] : {:.2} 
1273  CPU (4) freq [Hz] : {} | {} | {} | {} 
1274  Disc usage   [%]  : {} 
1275  Uptime       [s]  : {}>",
1276           self.cpu0_temp,
1277           self.cpu1_temp,
1278           self.cpu_temp,
1279           self.mb_temp,
1280           self.cpu_freq[0],
1281           self.cpu_freq[1],
1282           self.cpu_freq[2],
1283           self.cpu_freq[3],
1284           self.disk_usage,
1285           self.uptime)
1286  }
1287}
1288
1289impl Packable for CPUMoniData {
1290  const PACKET_TYPE : PacketType = PacketType::CPUMoniData;
1291}
1292
1293impl Serialization for CPUMoniData {
1294  
1295  const SIZE : usize = 41;
1296  const HEAD : u16   = 0xAAAA;
1297  const TAIL : u16   = 0x5555;
1298
1299  fn to_bytestream(&self) -> Vec<u8> {
1300    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
1301    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
1302    stream.extend_from_slice(&self.uptime  .to_le_bytes());
1303    stream.extend_from_slice(&self.disk_usage  .to_le_bytes());
1304    for k in 0..4 {
1305      stream.extend_from_slice(&self.cpu_freq[k].to_le_bytes());
1306    }
1307    stream.extend_from_slice(&self.cpu_temp .to_le_bytes());
1308    stream.extend_from_slice(&self.cpu0_temp.to_le_bytes());
1309    stream.extend_from_slice(&self.cpu1_temp.to_le_bytes());
1310    stream.extend_from_slice(&self.mb_temp  .to_le_bytes());
1311    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
1312    stream
1313  }
1314
1315  fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
1316    -> Result<Self, SerializationError> {
1317    Self::verify_fixed(stream, pos)?;
1318    let mut moni = CPUMoniData::new();
1319    moni.uptime     = parse_u32(stream, pos); 
1320    moni.disk_usage = parse_u8(stream, pos); 
1321    for k in 0..4 {
1322      moni.cpu_freq[k] = parse_u32(stream, pos);
1323    }
1324    moni.cpu_temp   = parse_f32(stream, pos);
1325    moni.cpu0_temp  = parse_f32(stream, pos);
1326    moni.cpu1_temp  = parse_f32(stream, pos);
1327    moni.mb_temp    = parse_f32(stream, pos);
1328    *pos += 2;
1329    Ok(moni)
1330  }
1331}
1332
1333impl MoniData for CPUMoniData {
1334
1335  fn get_board_id(&self) -> u8 {
1336    return 0;
1337  }
1338  
1339  fn get(&self, varname : &str) -> Option<f32> {
1340    match varname {
1341      "uptime"     =>    Some(self.uptime as f32),
1342      "disk_usage" =>    Some(self.disk_usage as f32),
1343      "cpu_freq0"  =>    Some(self.cpu_freq[0] as f32),
1344      "cpu_freq1"  =>    Some(self.cpu_freq[1] as f32),
1345      "cpu_freq2"  =>    Some(self.cpu_freq[2] as f32),
1346      "cpu_freq3"  =>    Some(self.cpu_freq[0] as f32),
1347      "cpu_temp"   =>    Some(self.cpu_temp),
1348      "cpu0_temp"  =>    Some(self.cpu0_temp),
1349      "cpu1_temp"  =>    Some(self.cpu1_temp),
1350      "mb_temp"    =>    Some(self.mb_temp),
1351      _            =>    None
1352    }
1353  }
1354  
1355  fn keys() -> Vec<&'static str> {
1356    vec![
1357      "uptime"     ,
1358      "disk_usage" ,
1359      "cpu_freq0"  ,
1360      "cpu_freq1"  ,
1361      "cpu_freq2"  ,
1362      "cpu_freq3"  ,
1363      "cpu_temp"   ,
1364      "cpu0_temp"  ,
1365      "cpu1_temp"  ,
1366      "mb_temp"]
1367  }
1368}
1369
1370#[cfg(feature = "random")]
1371impl FromRandom for CPUMoniData {
1372    
1373  fn from_random() -> Self {
1374    let mut moni    = Self::new();
1375    let mut rng     = rand::thread_rng();
1376    moni.uptime     = rng.gen::<u32>();
1377    moni.disk_usage = rng.gen::<u8>();
1378    for k in 0..4 {
1379      moni.cpu_freq[k] = rng.gen::<u32>();
1380    }
1381    moni.cpu_temp   = rng.gen::<f32>();
1382    moni.cpu0_temp  = rng.gen::<f32>();
1383    moni.cpu1_temp  = rng.gen::<f32>();
1384    moni.mb_temp    = rng.gen::<f32>();
1385    moni
1386  }
1387}
1388
1389///////////////////////////////////////////////////////
1390
1391/// Monitoring the MTB
1392#[derive(Debug, Copy, Clone, PartialEq)]
1393pub struct MtbMoniData {
1394  pub tiu_busy_len : u32,
1395  /// tiu_status\[0\] = emu_mode
1396  /// tiu_status\[1\] = use_aux_link
1397  /// tiu_status\[2\] = tiu_bad
1398  /// tiu_status\[3\] = bsy_stuck
1399  /// tiu_status\[4\] = ignore_bsy
1400  pub tiu_status   : u8,
1401  ///// Prescale factor in per cent
1402  ///// (might not be accurate)
1403  //pub prescale     : f16,
1404  //pub rsvd         : u8,
1405  pub daq_queue_len: u16,
1406  //pub vccpaux      : u16, 
1407  //pub vccoddr      : u16, 
1408  pub temp         : u16, 
1409  /// Unfortunatly at this point we only have
1410  /// a single byte left
1411  pub rb_lost_rate : u8,
1412  pub rate         : u16, 
1413  pub lost_rate    : u16, 
1414  pub vccint       : u16, 
1415  pub vccbram      : u16, 
1416  pub vccaux       : u16, 
1417}
1418
1419impl MtbMoniData {
1420  
1421  pub fn new() -> Self {
1422    Self {
1423      tiu_busy_len  : u32::MAX,
1424      tiu_status    : u8::MAX,
1425      //rsvd          : u8::MAX,
1426      //prescale      : f16::MAX,
1427      daq_queue_len : u16::MAX,
1428      temp          : u16::MAX,
1429      vccint        : u16::MAX,
1430      vccaux        : u16::MAX,
1431      vccbram       : u16::MAX,
1432      rate          : u16::MAX,
1433      lost_rate     : u16::MAX,
1434      rb_lost_rate  : u8::MAX
1435    }
1436  }
1437
1438  pub fn get_tiu_emulation_mode(&self) -> bool {
1439    self.tiu_status & 0x1 > 0
1440  }
1441  
1442  pub fn get_tiu_use_aux_link(&self) -> bool {
1443    self.tiu_status & 0x2 > 0
1444  }
1445
1446  pub fn get_tiu_bad(&self) -> bool { 
1447    self.tiu_status & 0x4 > 0
1448  }
1449
1450  pub fn get_tiu_busy_stuck(&self) -> bool {
1451    self.tiu_status & 0x8 > 0
1452  }
1453
1454  pub fn get_tiu_ignore_busy(&self) -> bool {
1455    self.tiu_status & 0x10 > 0
1456  }
1457
1458
1459  /// Convert ADC temp from adc values to Celsius
1460  pub fn get_fpga_temp(&self) -> f32 {
1461    self.temp as f32 * 503.975 / 4096.0 - 273.15
1462  }
1463  
1464  /// Convert ADC VCCINT from adc values to Voltage
1465  pub fn adc_vcc_conversion(data : u16) -> f32 {
1466    3.0 * data as f32 / (2_u32.pow(12-1)) as f32
1467  }
1468
1469  //pub fn set_prescale(&mut self, prescale : f32) {
1470  //  self.prescale = f16::from_f32(prescale);
1471  //}
1472
1473  //pub fn get_prescale(&self) -> f32 {
1474  //  self.prescale.to_f32()  
1475  //}
1476}
1477
1478impl Default for MtbMoniData {
1479  fn default() -> Self {
1480    Self::new()
1481  }
1482}
1483
1484impl fmt::Display for MtbMoniData {
1485  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1486    write!(f, "<MtbMoniData:
1487  MTB  EVT RATE  [Hz] {}
1488  LOST EVT RATE  [Hz] {}
1489  LOST RB EVT R  [Hz] {}
1490  TIU BUSY CNT  [CLK] {}
1491  DAQ QUEUE LEN       {}
1492  --- TIU STATUS ---
1493    EMU MODE          {}
1494    USE AUX LINK      {}
1495    TIU BAD           {}
1496    BUSY STUCK        {}
1497    IGNORE BUSY       {}
1498  --- --- --- --- --
1499  FPGA TEMP      [\u{00B0}C] {:.2}
1500  VCCINT          [V] {:.3}
1501  VCCAUX          [V] {:.3},
1502  VCCBRAM         [V] {:.3}>",
1503           self.rate,
1504           self.lost_rate,
1505           self.rb_lost_rate,
1506           self.tiu_busy_len,
1507           self.daq_queue_len,
1508           //self.get_prescale(),
1509           self.get_tiu_emulation_mode(),
1510           self.get_tiu_use_aux_link(),
1511           self.get_tiu_bad(),
1512           self.get_tiu_busy_stuck(),
1513           self.get_tiu_ignore_busy(),
1514           self.get_fpga_temp(),
1515           MtbMoniData::adc_vcc_conversion(self.vccint    ),
1516           MtbMoniData::adc_vcc_conversion(self.vccaux    ),
1517           MtbMoniData::adc_vcc_conversion(self.vccbram   ),
1518           )
1519  }
1520}
1521
1522impl Packable for MtbMoniData {
1523  const PACKET_TYPE : PacketType = PacketType::MonitorMtb;
1524}
1525
1526impl Serialization for MtbMoniData {
1527  
1528  const SIZE : usize = 24;
1529  const HEAD : u16   = 0xAAAA;
1530  const TAIL : u16   = 0x5555;
1531
1532  fn to_bytestream(&self) -> Vec<u8> {
1533    let mut stream = Vec::<u8>::with_capacity(Self::SIZE);
1534    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
1535    stream.extend_from_slice(&self.tiu_busy_len.to_le_bytes());
1536    stream.extend_from_slice(&self.tiu_status .to_le_bytes());
1537    //stream.extend_from_slice(&self.rsvd.to_le_bytes());
1538    stream.extend_from_slice(&self.rb_lost_rate.to_le_bytes());
1539    stream.extend_from_slice(&self.daq_queue_len.to_le_bytes());
1540    stream.extend_from_slice(&self.temp       .to_le_bytes());
1541    stream.extend_from_slice(&self.vccint     .to_le_bytes()); 
1542    stream.extend_from_slice(&self.vccaux     .to_le_bytes()); 
1543    stream.extend_from_slice(&self.vccbram    .to_le_bytes()); 
1544    //stream.extend_from_slice(&self.prescale   .to_le_bytes());
1545    //stream.extend_from_slice(&self.rb_lost_rate.to_le_bytes());
1546    stream.extend_from_slice(&self.rate       .to_le_bytes()); 
1547    stream.extend_from_slice(&self.lost_rate  .to_le_bytes());
1548    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
1549    stream
1550  }
1551
1552  fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
1553    -> Result<Self, SerializationError> {
1554    let mut moni_data      = Self::new();
1555    Self::verify_fixed(stream, pos)?;
1556    moni_data.tiu_busy_len  = parse_u32(&stream, pos);
1557    moni_data.tiu_status    = parse_u8(&stream, pos);
1558    //moni_data.rsvd          = parse_u8(&stream, pos);
1559    moni_data.rb_lost_rate  = parse_u8(&stream, pos);
1560    moni_data.daq_queue_len = parse_u16(&stream, pos);
1561    moni_data.temp          = parse_u16(&stream, pos);
1562    moni_data.vccint        = parse_u16(&stream, pos);
1563    //moni_data.prescale      = parse_f16(&stream, pos);
1564    moni_data.vccaux        = parse_u16(&stream, pos);
1565    moni_data.vccbram       = parse_u16(&stream, pos);
1566    //moni_data.rb_lost_rate  = parse_u16(&stream, pos);
1567    moni_data.rate          = parse_u16(&stream, pos);
1568    moni_data.lost_rate     = parse_u16(&stream, pos);
1569    *pos += 2; // since we deserialized the tail earlier and 
1570              // didn't account for it
1571    Ok(moni_data)
1572  }
1573}
1574
1575impl MoniData for MtbMoniData {
1576
1577  fn get_board_id(&self) -> u8 {
1578    return 0;
1579  }
1580  
1581  fn get(&self, varname : &str) -> Option<f32> {
1582    match varname {
1583      "board_id"     => Some(0.0f32),
1584      "tiu_busy_len" => Some(self.tiu_busy_len as f32), 
1585      "tiu_status"   => Some(self.tiu_status as f32), 
1586      "daq_queue_len"  => Some(self.daq_queue_len as f32), 
1587      //"prescale"     => Some(self.get_prescale()),
1588      "temp"         => Some(self.get_fpga_temp()), 
1589      "vccint"       => Some(Self::adc_vcc_conversion(self.vccint)), 
1590      "vccaux"       => Some(Self::adc_vcc_conversion(self.vccaux)), 
1591      "vccbram"      => Some(Self::adc_vcc_conversion(self.vccbram)), 
1592      "rate"         => Some(self.rate as f32), 
1593      "lost_rate"    => Some(self.lost_rate as f32), 
1594      "rb_lost_rate" => Some(self.rb_lost_rate as f32), 
1595      _              => None
1596    }
1597  }
1598  
1599  fn keys() -> Vec<&'static str> {
1600    vec![
1601      "board_id"      ,  
1602      "tiu_busy_len"  , 
1603      "tiu_status"    , 
1604      "daq_queue_len" , 
1605      "temp"          , 
1606      "vccint"        , 
1607      "vccaux"        , 
1608      "vccbram"       , 
1609      "rb_lost_rate"  ,
1610      "rate"          , 
1611      "lost_rate"] 
1612  }
1613}
1614
1615#[cfg(feature = "random")]
1616impl FromRandom for MtbMoniData {
1617  fn from_random() -> Self {
1618    let mut moni      = Self::new();
1619    let mut rng       = rand::thread_rng();
1620    moni.tiu_busy_len = rng.gen::<u32>();
1621    moni.tiu_status   = rng.gen::<u8>();
1622    //moni.prescale     = f16::from_f32(rng.gen::<f32>());
1623    moni.daq_queue_len= rng.gen::<u16>();
1624    moni.temp         = rng.gen::<u16>();
1625    moni.vccint       = rng.gen::<u16>();
1626    moni.vccaux       = rng.gen::<u16>();
1627    moni.vccbram      = rng.gen::<u16>();
1628    moni.rb_lost_rate = rng.gen::<u8>();
1629    moni.rate         = rng.gen::<u16>();
1630    moni.lost_rate    = rng.gen::<u16>();
1631    moni
1632  }
1633}
1634
1635  
1636#[test]
1637#[cfg(feature = "random")]
1638fn pack_ltbmonidata() {
1639  for _ in 0..100 {
1640    let data = LTBMoniData::from_random();
1641    let test : LTBMoniData = data.pack().unpack().unwrap();
1642    assert_eq!(data, test);
1643  }
1644}
1645
1646#[test]
1647#[cfg(feature = "random")]
1648fn pack_pamonidata() {
1649  for _ in 0..100 {
1650    let data = PAMoniData::from_random();
1651    let test : PAMoniData = data.pack().unpack().unwrap();
1652    assert_eq!(data, test);
1653  }
1654}
1655
1656#[test]
1657#[cfg(feature = "random")]
1658fn pack_pbmonidata() {
1659  for _ in 0..100 {
1660    let data = PBMoniData::from_random();
1661    let test : PBMoniData = data.pack().unpack().unwrap();
1662    assert_eq!(data, test);
1663  }
1664}
1665
1666#[test]
1667#[cfg(feature = "random")]
1668fn pack_mtbmonidata() {
1669  for _ in 0..100 {
1670    let data = MtbMoniData::from_random();
1671    let test : MtbMoniData = data.pack().unpack().unwrap();
1672    assert_eq!(data, test);
1673  }
1674}
1675
1676#[test]
1677#[cfg(feature = "random")]
1678fn pack_rbmonidata() {
1679  for _ in 0..100 {
1680    let data = RBMoniData::from_random();
1681    let test : RBMoniData = data.pack().unpack().unwrap();
1682    assert_eq!(data, test);
1683  }
1684}
1685
1686#[test]
1687#[cfg(feature = "random")]
1688fn monidata_pamonidata() {
1689  let data = PAMoniData::from_random();
1690  for k in PAMoniData::keys() {
1691    assert!(data.get(k).is_some());
1692  }
1693  assert_eq!(data.get_board_id(), data.board_id);
1694}
1695
1696#[test]
1697#[cfg(feature = "random")]
1698fn monidata_pbmonidata() {
1699  let data = PBMoniData::from_random();
1700  for k in PBMoniData::keys() {
1701    assert!(data.get(k).is_some());
1702  }
1703  assert_eq!(data.get_board_id(), data.board_id);
1704}
1705
1706#[test]
1707#[cfg(feature = "random")]
1708fn monidata_ltbmonidata() {
1709  let data = LTBMoniData::from_random();
1710  for k in LTBMoniData::keys() {
1711    assert!(data.get(k).is_some());
1712  }
1713  assert_eq!(data.get_board_id(), data.board_id);
1714}
1715
1716#[test]
1717#[cfg(feature = "random")]
1718fn monidata_rbmonidata() {
1719  let data = RBMoniData::from_random();
1720  for k in RBMoniData::keys() {
1721    assert!(data.get(k).is_some());
1722  }
1723  assert_eq!(data.get_board_id(), data.board_id);
1724}
1725
1726#[test]
1727#[cfg(feature = "random")]
1728fn monidata_cpumonidata() {
1729  let data = CPUMoniData::from_random();
1730  for k in CPUMoniData::keys() {
1731    assert!(data.get(k).is_some());
1732  }
1733  assert_eq!(data.get_board_id(), 0u8);
1734}
1735
1736#[test]
1737#[cfg(feature = "random")]
1738fn monidata_mtbmonidata() {
1739  let data = MtbMoniData::from_random();
1740  for k in MtbMoniData::keys() {
1741    assert!(data.get(k).is_some());
1742  }
1743  assert_eq!(data.get_board_id(), 0u8);
1744}
1745
1746
1747#[test]
1748#[cfg(feature = "random")]
1749fn pack_cpumonidata() {
1750  for _ in 0..100 {
1751    let data = CPUMoniData::from_random();
1752    let test : CPUMoniData = data.pack().unpack().unwrap();
1753    assert_eq!(data, test);
1754  }
1755}
1756