1pub mod pa_moni_data;
5pub use pa_moni_data::{
6 PAMoniData,
7 PAMoniDataSeries
8};
9pub mod pb_moni_data;
10pub use pb_moni_data::{
11 PBMoniData,
12 PBMoniDataSeries
13};
14pub mod mtb_moni_data;
15pub use mtb_moni_data::{
16 MtbMoniData,
17 MtbMoniDataSeries
18};
19pub mod ltb_moni_data;
20pub use ltb_moni_data::{
21 LTBMoniData,
22 LTBMoniDataSeries
23};
24pub mod rb_moni_data;
25pub use rb_moni_data::{
26 RBMoniData,
27 RBMoniDataSeries
28};
29pub mod cpu_moni_data;
30pub use cpu_moni_data::{
31 CPUMoniData,
32 CPUMoniDataSeries
33};
34
35pub mod heartbeats;
36pub use heartbeats::{
37 DataSinkHB,
38 DataSinkHBSeries,
39 MasterTriggerHB,
40 MasterTriggerHBSeries,
41 EventBuilderHB,
42 EventBuilderHBSeries,
43};
44
45pub mod run_statistics;
46pub use run_statistics::RunStatistics;
47
48pub mod sip_position;
49pub use sip_position::{
50 SipPosMoniData,
51 SipPosMoniDataSeries
52};
53
54pub mod sip_pressure;
55pub use sip_pressure::{
56 SipPresMoniData,
57 SipPresMoniDataSeries,
58};
59
60pub mod sip_time;
61pub use sip_time::{
62 SipTimeMoniData,
63 SipTimeMoniDataSeries
64};
65
66pub mod gcu_ev_stats;
67pub use gcu_ev_stats::{
68 GcuEvBldStatsMoniData,
69 GcuEvBldStatsMoniDataSeries
70};
71
72pub mod tracker_gps;
73pub use tracker_gps::{
74 TrackerGpsMoniData,
75 TrackerGpsMoniDataSeries
76};
77
78pub mod cooling;
79pub use cooling::{
80 CoolingMoniData,
81 CoolingMoniDataSeries
82};
83
84pub mod wastie;
85pub use wastie::*;
86
87use std::collections::VecDeque;
88use std::collections::HashMap;
89
90#[cfg(feature="pybindings")]
91use crate::prelude::*;
92
93#[cfg(feature="pybindings")]
94use polars::frame::column::Column;
95#[cfg(feature="pybindings")]
96use polars::prelude::NamedFrom;
97
98pub trait MoniData {
101 fn get_board_id(&self) -> u8;
110
111 fn get(&self, varname : &str) -> Option<f32>;
113
114 fn keys() -> Vec<&'static str>;
116
117 fn get_timestamp(&self) -> u64 {
118 0
119 }
120
121 fn set_timestamp(&mut self, _ts : u64) {
122 }
123}
124
125pub trait MoniSeries<T>
146 where T : Copy + MoniData {
147
148 fn get_first_ts(&self) -> u64;
149
150 fn get_data(&self) -> &HashMap<u8,VecDeque<T>>;
151
152 fn get_data_mut(&mut self) -> &mut HashMap<u8,VecDeque<T>>;
153
154 fn get_max_size(&self) -> usize;
155
156 fn set_max_size(&mut self, size : usize);
157
158 fn get_timestamps(&self) -> &Vec<u64>;
159
160 fn add_timestamp(&mut self, ts : u64);
161
162 fn get_var(&self, varname : &str) -> HashMap<u8, Vec<f32>> {
164 let mut values = HashMap::<u8, Vec<f32>>::new();
165 for k in self.get_data().keys() {
166 match self.get_var_for_board(varname, k) {
167 None => (),
168 Some(vals) => {
169 values.insert(*k, vals);
170 }
171 }
172 }
187 values
188 }
189
190 fn get_var_for_board(&self, varname : &str, rb_id : &u8) -> Option<Vec<f32>> {
192 let mut values = Vec::<f32>::new();
193 match self.get_data().get(&rb_id) {
194 None => (),
195 Some(vec_moni) => {
196 for moni in vec_moni {
197 match moni.get(varname) {
198 None => {
199 return None;
200 },
201 Some(val) => {
202 values.push(val);
203 }
204 }
205 }
206 }
207 }
208 Some(values)
211 }
212
213 #[cfg(feature = "pybindings")]
214 fn get_dataframe(&self) -> PolarsResult<DataFrame> {
215 let mut series = Vec::<Column>::new();
216 for k in Self::keys() {
217 match self.get_series(k) {
218 None => {
219 error!("Unable to get series for {}", k);
220 }
221 Some(ser) => {
222 series.push(ser.into());
224 }
225 }
226 }
227 let df = DataFrame::new(series)?;
234 Ok(df)
235 }
236
237 #[cfg(feature = "pybindings")]
238 fn get_series(&self, varname : &str) -> Option<Series> {
247 let mut data = Vec::<f32>::with_capacity(self.get_data().len());
248 let sorted_keys: Vec<u8> = self.get_data().keys().cloned().collect();
249 for board_id in sorted_keys.iter() {
250 let dqe = self.get_data().get(board_id).unwrap(); for moni in dqe {
252 match moni.get(varname) {
253 None => {
254 error!("This type of MoniData does not have a key called {}", varname);
255 return None;
256 }
257 Some(var) => {
258 data.push(var);
259 }
260 }
261 }
262 }
263 let series = Series::new(varname.into(), data);
264 Some(series)
265 }
266
267 fn keys() -> Vec<&'static str> {
269 T::keys()
270 }
271
272 fn get_board_ids(&self) -> Vec<u8> {
274 self.get_data().keys().cloned().collect()
275 }
276
277 fn add(&mut self, data : T) {
279 let board_id = data.get_board_id();
280 if !self.get_data().contains_key(&board_id) {
281 self.get_data_mut().insert(board_id, VecDeque::<T>::new());
282 }
283 self.get_data_mut().get_mut(&board_id).unwrap().push_back(data);
284 if self.get_data_mut().get_mut(&board_id).unwrap().len() > self.get_max_size() {
285 error!("The queue is too large, returning the first element! If you need a larger series size, set the max_size field");
286 self.get_data_mut().get_mut(&board_id).unwrap().pop_front();
287 }
288 }
289
290 fn get_last_moni(&self, board_id : u8) -> Option<T> {
291 let size = self.get_data().get(&board_id)?.len();
292 Some(self.get_data().get(&board_id).unwrap()[size - 1])
293 }
294}
295
296#[macro_export]
299macro_rules! moniseries_general {
300 ($name : ident, $class:ty) => {
301 use std::collections::VecDeque;
302 use std::collections::HashMap;
303
304 use crate::monitoring::MoniSeries;
305
306 #[cfg_attr(feature="pybindings",pyclass)]
307 #[derive(Debug, Clone, PartialEq)]
308 pub struct $name {
309 data : HashMap<u8, VecDeque<$class>>,
310 max_size : usize,
311 timestamps : Vec<u64>,
312 }
313
314 impl $name {
315 pub fn new() -> Self {
316 Self {
317 data : HashMap::<u8, VecDeque<$class>>::new(),
318 max_size : 10000,
319 timestamps : Vec::<u64>::new()
320 }
321 }
322 }
323
324 impl Default for $name {
325 fn default() -> Self {
326 Self::new()
327 }
328 }
329
330 impl fmt::Display for $name {
331 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
332 write!(f, "<{} : {} boards>", stringify!($name), self.data.len())
333 }
334 }
335
336 impl MoniSeries<$class> for $name {
337
338 fn get_first_ts(&self) -> u64 {
339 if self.timestamps.len() == 0 {
340 return 0;
341 } else {
342 self.timestamps[0]
343 }
344 }
345
346 fn get_data(&self) -> &HashMap<u8,VecDeque<$class>> {
347 return &self.data;
348 }
349
350 fn get_data_mut(&mut self) -> &mut HashMap<u8,VecDeque<$class>> {
351 return &mut self.data;
352 }
353
354 fn get_max_size(&self) -> usize {
355 return self.max_size;
356 }
357
358 fn set_max_size(&mut self, size : usize) {
359 self.max_size = size;
360 }
361
362 fn add_timestamp(&mut self, ts : u64) {
363 self.timestamps.push(ts);
364 }
365
366 fn get_timestamps(&self) -> &Vec<u64> {
367 return &self.timestamps;
372 }
373 }
374
375 #[cfg(feature="pybindings")]
376 #[pymethods]
377 impl $name {
378 #[new]
379 fn new_py() -> Self {
380 Self::new()
381 }
382
383 #[pyo3(name="keys")]
384 #[staticmethod]
385 fn keys_py() -> Vec<&'static str> {
386 Self::keys()
387 }
388
389 #[getter]
392 #[pyo3(name="max_size")]
393 fn get_max_size_py(&self) -> usize {
394 self.get_max_size()
395 }
396
397 #[setter]
398 #[pyo3(name="max_size")]
399 fn set_max_size_py(&mut self, size : usize) {
400 self.set_max_size(size);
401 }
402
403 #[getter]
404 #[pyo3(name="first_ts")]
405 pub fn get_first_ts_py(&self) -> u64 {
406 self.get_first_ts()
407 }
408
409 #[getter]
413 #[pyo3(name="timestamps")]
414 fn get_timestamps_py(&self) -> Vec<u64> {
415 warn!("This returns a full copy and is a performance bottleneck!");
416 return self.timestamps.clone();
417 }
418
419 #[pyo3(name="add_timestamp")]
426 fn add_timestamp_py(&mut self, ts : u64) {
427 self.timestamps.push(ts);
428 }
429
430 #[pyo3(name="add")]
432 fn add_py(&mut self, moni : $class) {
433 self.add(moni);
434 }
435
436 #[pyo3(name="get_var_for_board")]
437 fn get_var_for_board_py(&self, varname : &str, rb_id : u8) -> Option<Vec<f32>> {
438 self.get_var_for_board(varname, &rb_id)
439 }
440
441 #[pyo3(name="get_dataframe")]
444 fn get_dataframe_py(&self) -> PyResult<PyDataFrame> {
445 match self.get_dataframe() {
446 Ok(df) => {
447 let pydf = PyDataFrame(df);
448 return Ok(pydf);
449 },
450 Err(err) => {
451 return Err(PyValueError::new_err(err.to_string()));
452 }
453 }
454 }
455 }
456 #[cfg(feature="pybindings")]
457 pythonize_display!($name);
458 }
459}
460
461#[macro_export]
465macro_rules! moniseries {
466 ($name : ident, $class:ty) => {
467
468 moniseries_general!($name, $class);
469
470 #[cfg(feature="pybindings")]
471 #[pymethods]
472 impl $name {
473
474 #[pyo3(signature = (filename, from_object = CRFrameObjectType::TelemetryPacket))]
490 fn add_crfile(&mut self, filename : String, from_object : CRFrameObjectType) {
491 let reader = CRReader::new(filename).expect("Unable to open file!");
492 let tp_source = String::from("TofPacketType.") + stringify!($class);
499 let tp_source_alt = String::from("PacketType.") + stringify!($class);
500 let tel_source = "TelemetryPacketType.AnyTofHK";
501 for frame in reader {
502 match from_object {
503 CRFrameObjectType::TofPacket => {
504 if frame.has(&tp_source) || frame.has(&tp_source_alt) {
505 if frame.has(&tp_source) {
506 let moni_res = frame.get::<TofPacket>(&tp_source).unwrap().unpack::<$class>();
507 match moni_res {
508 Err(err) => {
509 println!("Error unpacking! {err}");
510 }
511 Ok(moni) => {
512 self.add(moni);
513 }
514 }
515 }
516 if frame.has(&tp_source_alt) {
517 let moni_res = frame.get::<TofPacket>(&tp_source_alt).unwrap().unpack::<$class>();
518 match moni_res {
519 Err(err) => {
520 println!("Error unpacking! {err}");
521 }
522 Ok(moni) => {
523 self.add(moni);
524 }
525 }
526 }
527 }
528 }
529 CRFrameObjectType::TelemetryPacket | CRFrameObjectType::Unknown => {
530 if frame.has(tel_source) {
531 let hk_res = frame.get::<TelemetryPacket>(tel_source);
532 match hk_res {
533 Err(err) => {
534 println!("Error unpacking! {err}");
535 }
536 Ok(hk) => {
537 let mut pos = 0;
538 let gcutime = hk.header.get_gcutime() as u64;
541 match TofPacket::from_bytestream(&hk.payload, &mut pos) {
542 Err(err) => {
543 println!("Error unpackin! {err}");
544 }
545 Ok(tp) => {
546 if tp.packet_type == <$class>::TOF_PACKET_TYPE {
547 match tp.unpack::<$class>() {
548 Err(err) => {
549 println!("Error unpacking! {err}");
550 }
551 Ok(mut moni) => {
552 self.add_timestamp(gcutime);
553 moni.set_timestamp(gcutime - self.get_first_ts());
554 self.add(moni);
555 }
557 }
558 }
559 }
560 }
561 }
562 }
563 }
564 }
565 _ => () }
567 }
568 }
569
570 fn add_telemetryfile(&mut self, filename : String) {
575 let reader = TelemetryPacketReader::new(filename, true, None, None, 0, 0);
576 for pack in reader {
577 if pack.header.packet_type == TelemetryPacketType::AnyTofHK {
578 let mut pos = 0;
579 let gcutime = pack.header.get_gcutime() as u64;
582 match TofPacket::from_bytestream(&pack.payload, &mut pos) {
583 Err(err) => {
584 println!("Error unpackin! {err}");
585 }
586 Ok(tp) => {
587 if tp.packet_type == <$class>::TOF_PACKET_TYPE {
588 match tp.unpack::<$class>() {
589 Err(err) => {
590 println!("Error unpacking! {err}");
591 }
592 Ok(mut moni) => {
593 self.add_timestamp(gcutime);
594 moni.set_timestamp(gcutime - self.get_first_ts());
595 self.add(moni);
596 }
598 }
599 }
600 }
601 }
602 }
603 }
604 }
605
606 #[pyo3(signature = (filename))]
618 fn add_toffile(&mut self, filename : String) {
619 let reader = TofPacketReader::new(&filename);
620 for tp in reader {
621 if tp.packet_type == <$class>::TOF_PACKET_TYPE {
622 match tp.unpack::<$class>() {
623 Err(err) => {
624 println!("Error unpacking! {err}");
625 }
626 Ok(mut moni) => {
627 self.add_timestamp(moni.get_timestamp());
628 moni.set_timestamp(moni.get_timestamp());
629 self.add(moni);
630 }
632 }
633 }
634 }
635 }
636
637 #[staticmethod]
646 fn from_tof_file(filename : String) -> PyResult<PyDataFrame> {
647 let mut reader = TofPacketReader::new(&filename);
648 let mut series = Self::new();
649 reader.filter = <$class>::TOF_PACKET_TYPE;
652 for tp in reader {
653 if let Ok(moni) = tp.unpack::<$class>() {
654 series.add(moni);
655 }
656 }
658 match series.get_dataframe() {
659 Ok(df) => {
660 let pydf = PyDataFrame(df);
661 return Ok(pydf);
662 },
663 Err(err) => {
664 return Err(PyValueError::new_err(err.to_string()));
665 }
666 }
667 }
668 }
669 }
670}
671
672#[macro_export]
680macro_rules! moniseries_telemetry {
681 ($name : ident, $class:ty) => {
682
683 moniseries_general!($name, $class);
684
685 #[cfg(feature="pybindings")]
686 #[pymethods]
687 impl $name {
688
689 #[pyo3(signature = (filename, from_object = CRFrameObjectType::TelemetryPacket))]
701 fn add_crfile(&mut self, filename : String, from_object : CRFrameObjectType) {
702 let reader = CRReader::new(filename).expect("Unable to open file!");
703 let tel_source = "TelemetryPacketType.AnyTofHK";
710 for frame in reader {
711 match from_object {
712 CRFrameObjectType::TelemetryPacket | CRFrameObjectType::Unknown => {
713 if frame.has(tel_source) {
714 let hk_res = frame.get::<TelemetryPacket>(tel_source);
715 match hk_res {
716 Err(err) => {
717 println!("Error unpacking! {err}");
718 }
719 Ok(hk) => {
720 if hk.header.packet_type != <$class>::TEL_PACKET_TYPE {
721 continue;
723 }
724 let mut pos = 0;
725 let gcutime = hk.header.get_gcutime() as u64;
728 match <$class>::from_bytestream(&hk.payload, &mut pos) {
729 Err(err) => {
730 println!("Error unpackin! {err}");
731 }
732 Ok(mut moni) => {
733 self.add_timestamp(gcutime);
734 moni.set_timestamp(gcutime - self.get_first_ts());
735 self.add(moni);
736 }
738 }
739 }
740 }
741 }
742 }
743 _ => ()
744 }
745 }
746 }
747
748 fn add_telemetryfile(&mut self, filename : String) {
753 let reader = TelemetryPacketReader::new(filename, true, None, None, 0, 0);
754 for pack in reader {
755 if pack.header.packet_type == <$class>::TEL_PACKET_TYPE {
756 let mut pos = 0;
757 let gcutime = pack.header.get_gcutime() as u64;
760 match <$class>::from_bytestream(&pack.payload, &mut pos) {
761 Err(err) => {
762 println!("Error unpackin! {err}");
763 }
764 Ok(mut moni) => {
765 self.add_timestamp(gcutime);
766 moni.set_timestamp(gcutime - self.get_first_ts());
767 self.add(moni);
768 }
769 }
770 }
771 }
772 }
773 }
774 }
775}
776
777