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 #[getter]
437 #[pyo3(name="boards")]
438 fn get_boards(&self) -> Vec<u16> {
439 let mut boards = Vec::<u16>::new();
442 for k in self.data.keys() {
443 boards.push(*k as u16);
444 }
445 boards
446 }
447
448 #[getter]
453 #[pyo3(name="sizes")]
454 fn get_sizes(&self) -> HashMap<u16,usize> {
455 let mut boards = HashMap::<u16,usize>::new();
458 for k in self.data.keys() {
459 boards.insert(*k as u16, self.data[k].len());
460 }
461 boards
462 }
463
464 #[pyo3(name="get_var_for_board")]
465 fn get_var_for_board_py(&self, varname : &str, rb_id : u8) -> Option<Vec<f32>> {
466 self.get_var_for_board(varname, &rb_id)
467 }
468
469 #[pyo3(name="get_monidata_for_board")]
470 fn get_monidata_for_board(&self, board_id : u8, idx : usize) -> Option<$class> {
471 if !self.data.contains_key(&board_id) {
472 return None;
473 }
474 if self.data.get(&board_id).unwrap().len() < idx + 1 {
475 return None;
476 } else {
477 return Some(self.data.get(&board_id).unwrap()[idx].clone());
478 }
479 }
480
481 #[pyo3(name="get_dataframe")]
484 fn get_dataframe_py(&self) -> PyResult<PyDataFrame> {
485 match self.get_dataframe() {
486 Ok(df) => {
487 let pydf = PyDataFrame(df);
488 return Ok(pydf);
489 },
490 Err(err) => {
491 return Err(PyValueError::new_err(err.to_string()));
492 }
493 }
494 }
495 }
496 #[cfg(feature="pybindings")]
497 pythonize_display!($name);
498 }
499}
500
501#[macro_export]
505macro_rules! moniseries {
506 ($name : ident, $class:ty) => {
507
508 moniseries_general!($name, $class);
509
510 #[cfg(feature="pybindings")]
511 #[pymethods]
512 impl $name {
513
514 #[pyo3(signature = (filename, from_object = CRFrameObjectType::TelemetryPacket))]
530 fn add_crfile(&mut self, filename : String, from_object : CRFrameObjectType) {
531 let reader = CRReader::new(filename).expect("Unable to open file!");
532 let tp_source = String::from("TofPacketType.") + stringify!($class);
539 let tp_source_alt = String::from("PacketType.") + stringify!($class);
540 let tel_source = "TelemetryPacketType.AnyTofHK";
541 for frame in reader {
542 match from_object {
543 CRFrameObjectType::TofPacket => {
544 if frame.has(&tp_source) || frame.has(&tp_source_alt) {
545 if frame.has(&tp_source) {
546 let moni_res = frame.get::<TofPacket>(&tp_source).unwrap().unpack::<$class>();
547 match moni_res {
548 Err(err) => {
549 println!("Error unpacking! {err}");
550 }
551 Ok(moni) => {
552 self.add(moni);
553 }
554 }
555 }
556 if frame.has(&tp_source_alt) {
557 let moni_res = frame.get::<TofPacket>(&tp_source_alt).unwrap().unpack::<$class>();
558 match moni_res {
559 Err(err) => {
560 println!("Error unpacking! {err}");
561 }
562 Ok(moni) => {
563 self.add(moni);
564 }
565 }
566 }
567 }
568 }
569 CRFrameObjectType::TelemetryPacket | CRFrameObjectType::Unknown => {
570 if frame.has(tel_source) {
571 let hk_res = frame.get::<TelemetryPacket>(tel_source);
572 match hk_res {
573 Err(err) => {
574 println!("Error unpacking! {err}");
575 }
576 Ok(hk) => {
577 let mut pos = 0;
578 let gcutime = hk.header.get_gcutime() as u64;
581 match TofPacket::from_bytestream(&hk.payload, &mut pos) {
582 Err(err) => {
583 println!("Error unpackin! {err}");
584 }
585 Ok(tp) => {
586 if tp.packet_type == <$class>::TOF_PACKET_TYPE {
587 match tp.unpack::<$class>() {
588 Err(err) => {
589 println!("Error unpacking! {err}");
590 }
591 Ok(mut moni) => {
592 self.add_timestamp(gcutime);
593 moni.set_timestamp(gcutime - self.get_first_ts());
594 self.add(moni);
595 }
597 }
598 }
599 }
600 }
601 }
602 }
603 }
604 }
605 _ => () }
607 }
608 }
609
610 fn add_telemetryfile(&mut self, filename : String) {
615 let reader = TelemetryPacketReader::new(filename, true, None, None, 0, 0);
616 for pack in reader {
617 if pack.header.packet_type == TelemetryPacketType::AnyTofHK {
618 let mut pos = 0;
619 let gcutime = pack.header.get_gcutime() as u64;
622 match TofPacket::from_bytestream(&pack.payload, &mut pos) {
623 Err(err) => {
624 println!("Error unpackin! {err}");
625 }
626 Ok(tp) => {
627 if tp.packet_type == <$class>::TOF_PACKET_TYPE {
628 match tp.unpack::<$class>() {
629 Err(err) => {
630 println!("Error unpacking! {err}");
631 }
632 Ok(mut moni) => {
633 self.add_timestamp(gcutime);
634 moni.set_timestamp(gcutime - self.get_first_ts());
635 self.add(moni);
636 }
638 }
639 }
640 }
641 }
642 }
643 }
644 }
645
646 #[pyo3(signature = (filename))]
658 fn add_toffile(&mut self, filename : String) {
659 let reader = TofPacketReader::new(&filename);
660 for tp in reader {
661 if tp.packet_type == <$class>::TOF_PACKET_TYPE {
662 match tp.unpack::<$class>() {
663 Err(err) => {
664 println!("Error unpacking! {err}");
665 }
666 Ok(mut moni) => {
667 self.add_timestamp(moni.get_timestamp());
668 moni.set_timestamp(moni.get_timestamp());
669 self.add(moni);
670 }
672 }
673 }
674 }
675 }
676
677 #[staticmethod]
686 fn from_tof_file(filename : String) -> PyResult<PyDataFrame> {
687 let mut reader = TofPacketReader::new(&filename);
688 let mut series = Self::new();
689 reader.filter = <$class>::TOF_PACKET_TYPE;
692 for tp in reader {
693 if let Ok(moni) = tp.unpack::<$class>() {
694 series.add(moni);
695 }
696 }
698 match series.get_dataframe() {
699 Ok(df) => {
700 let pydf = PyDataFrame(df);
701 return Ok(pydf);
702 },
703 Err(err) => {
704 return Err(PyValueError::new_err(err.to_string()));
705 }
706 }
707 }
708 }
709 }
710}
711
712#[macro_export]
720macro_rules! moniseries_telemetry {
721 ($name : ident, $class:ty) => {
722
723 moniseries_general!($name, $class);
724
725 #[cfg(feature="pybindings")]
726 #[pymethods]
727 impl $name {
728
729 #[pyo3(signature = (filename, from_object = CRFrameObjectType::TelemetryPacket))]
741 fn add_crfile(&mut self, filename : String, from_object : CRFrameObjectType) {
742 let reader = CRReader::new(filename).expect("Unable to open file!");
743 let tel_source = "TelemetryPacketType.AnyTofHK";
750 for frame in reader {
751 match from_object {
752 CRFrameObjectType::TelemetryPacket | CRFrameObjectType::Unknown => {
753 if frame.has(tel_source) {
754 let hk_res = frame.get::<TelemetryPacket>(tel_source);
755 match hk_res {
756 Err(err) => {
757 println!("Error unpacking! {err}");
758 }
759 Ok(hk) => {
760 if hk.header.packet_type != <$class>::TEL_PACKET_TYPE {
761 continue;
763 }
764 let mut pos = 0;
765 let gcutime = hk.header.get_gcutime() as u64;
768 match <$class>::from_bytestream(&hk.payload, &mut pos) {
769 Err(err) => {
770 println!("Error unpackin! {err}");
771 }
772 Ok(mut moni) => {
773 self.add_timestamp(gcutime);
774 moni.set_timestamp(gcutime - self.get_first_ts());
775 self.add(moni);
776 }
778 }
779 }
780 }
781 }
782 }
783 _ => ()
784 }
785 }
786 }
787
788 fn add_telemetryfile(&mut self, filename : String) {
793 let reader = TelemetryPacketReader::new(filename, true, None, None, 0, 0);
794 for pack in reader {
795 if pack.header.packet_type == <$class>::TEL_PACKET_TYPE {
796 let mut pos = 0;
797 let gcutime = pack.header.get_gcutime() as u64;
800 match <$class>::from_bytestream(&pack.payload, &mut pos) {
801 Err(err) => {
802 println!("Error unpackin! {err}");
803 }
804 Ok(mut moni) => {
805 self.add_timestamp(gcutime);
806 moni.set_timestamp(gcutime - self.get_first_ts());
807 self.add(moni);
808 }
809 }
810 }
811 }
812 }
813 }
814 }
815}
816
817