1use std::time::Instant;
8use std::fs;
9use std::sync::{
10 Arc,
11 Mutex,
12};
13
14use std::collections::{
15 VecDeque,
16 HashMap,
17};
18
19use ndhistogram::{
20 Histogram,
21 Hist1D,
22 ndhistogram,
23};
24
25use ndhistogram::axis::{
26 Uniform,
27};
28
29use ratatui::prelude::Stylize;
30use ratatui::{
31 Frame,
34 layout::{Alignment, Constraint, Direction, Layout, Rect},
35 style::{
36 Modifier,
37 Style
38 },
39 text::{
40 Line
42 },
43 widgets::{
44 Block,
45 BorderType,
46 Borders,
47 List,
48 ListItem,
49 ListState,
50 Paragraph,
51 Row,
52 Table,
53 },
54};
55
56use crossbeam_channel::{
57 Receiver
58};
59
60
61use tof_dataclasses::packets::{
62 TofPacket,
63 PacketType
64};
65
66use tof_dataclasses::calibrations::RBCalibrations;
67use tof_dataclasses::errors::SerializationError;
68use tof_dataclasses::events::RBEvent;
69use tof_dataclasses::monitoring::{
71 RBMoniData,
72 LTBMoniData,
73 PAMoniData,
74 RBMoniDataSeries,
75 LTBMoniDataSeries,
76 PAMoniDataSeries,
77};
78
79use tof_dataclasses::series::MoniSeries;
80use tof_dataclasses::io::RBEventMemoryStreamer;
81use tof_dataclasses::database::ReadoutBoard;
82use tof_dataclasses::alerts::*;
83
84use crate::widgets::{
85 timeseries,
86 };
88
89use crate::colors::{
90 ColorTheme,
91};
92
93#[derive(Debug, Copy, Clone)]
94pub enum RBLTBListFocus {
95 RBList,
96 LTBList,
97}
98
99#[derive(Debug, Copy, Clone, PartialEq)]
100pub enum RBTabView {
101 Info,
102 Waveform,
103 RBMoniData,
104 PAMoniData,
105 PBMoniData,
106 LTBMoniData,
107 GlobalRates,
108 SelectRB,
109}
110
111#[derive(Debug, Clone)]
112pub struct RBTab<'a> {
113 pub tp_receiver : Receiver<TofPacket>,
114 pub rb_receiver : Receiver<RBEvent>,
115 pub rb_selector : u8,
116 pub rb_changed : bool,
117 pub rb_calibration : RBCalibrations,
118 pub cali_loaded : bool,
119 pub event_queue : VecDeque<RBEvent>,
120 pub moni_queue : RBMoniDataSeries,
121 pub global_rates : HashMap<u8, String>,
122 pub ltb_moni_queue : LTBMoniDataSeries,
123 pub pa_show_biases : bool,
124 pub pa_moni_queue : PAMoniDataSeries,
125 pub met_queue : VecDeque<f64>,
126 pub met_queue_moni : HashMap<u8,VecDeque<f64>>,
127 pub met_queue_ltb_moni : HashMap<u8,VecDeque<f64>>,
128 pub met_queue_pa_moni : HashMap<u8,VecDeque<f64>>,
129 pub ch_data : Vec<Vec<(f64,f64)>>,
131 pub fpgatmp_queue : VecDeque<(f64,f64)>,
133 pub fpgatmp_fr_moni : bool,
134
135 pub queue_size : usize,
136
137 pub n_events : usize,
138 pub n_moni : usize,
139 pub miss_evid : usize,
140 pub last_evid : u32,
141 pub nch_histo : Hist1D<Uniform<f32>>,
142 timer : Instant,
143
144 pub theme : ColorTheme,
145 pub view : RBTabView,
146
147 pub rbs : HashMap<u8, ReadoutBoard>,
148
149 pub list_focus : RBLTBListFocus,
150 pub rbl_state : ListState,
152 pub rbl_items : Vec::<ListItem<'a>>,
153 pub rbl_active : bool,
154 pub rb_to_rat : HashMap<u8,u8>,
156 pub alerts : Arc<Mutex<HashMap<&'a str,TofAlert<'a>>>>,
158 alerts_active : bool,
159 moni_old_check : HashMap<u8,Instant>,
160}
161
162impl RBTab<'_> {
163
164 pub fn new<'a>(tp_receiver : Receiver<TofPacket>,
165 rb_receiver : Receiver<RBEvent>,
166 rbs : HashMap<u8, ReadoutBoard>,
167 alerts : Arc<Mutex<HashMap<&'a str,TofAlert<'a>>>>,
168 theme : ColorTheme) -> RBTab<'a> {
169 let mut alerts_active = false;
171 match alerts.lock() {
172 Ok(al) => {
173 if al.len() > 0 {
174 alerts_active = true;
175 info!("Found {} active alerts!", al.len());
176 }
177 }
178 Err(err) => {
179 error!("Unable to lock alert mutex! {err}");
180 }
181 }
182 let rb_non_exist = vec![10,12,34,37,38,43,45,47,48,49];
183 let mut rb_select_items = Vec::<ListItem>::new();
184 let mut global_rates = HashMap::<u8,String>::new();
185 for k in 1..51 {
186 if rb_non_exist.contains(&k) {
187 continue;
188 }
189 global_rates.insert(k as u8, String::from("\u{203c} no data yet"));
190 }
191 let mut moni_old_check = HashMap::<u8, Instant>::new();
192 for k in 1..51 {
193 let this_item = format!(" RB{:0>2}", k);
194 rb_select_items.push(ListItem::new(Line::from(this_item)));
195 moni_old_check.insert(k, Instant::now());
196 }
197
198 let queue_size = 1000usize;
199 let mut ch_data = Vec::<Vec::<(f64,f64)>>::with_capacity(1024);
200 for _channel in 0..9 {
201 let tmp_vec = vec![(0.0f64,0.0f64);1024];
202 ch_data.push(tmp_vec);
204 }
205 let bins = Uniform::new(50,-0.5,49.5).unwrap();
206 let mut rbl_state = ListState::default();
207 rbl_state.select(Some(1));
208 warn!("Using hardcoded values for the RB->RAT hashmap!");
209 let rb_to_rat
211 = HashMap::<u8,u8>::from(
212 [(1, 10),
213 (2, 15),
214 (3, 1),
215 (4, 15),
216 (5, 20),
217 (6, 19),
218 (7, 17),
219 (8, 9),
220 (11,10),
221 (13, 4),
222 (14, 2),
223 (15, 1),
224 (16, 8),
225 (17,17),
226 (18,13),
227 (19, 7),
228 (20, 7),
229 (21, 5),
230 (22,11),
231 (23, 5),
232 (24, 6),
233 (25, 8),
234 (26,11),
235 (27, 6),
236 (28,20),
237 (29, 3),
238 (30, 9),
239 (31, 3),
240 (32, 2),
241 (33,18),
242 (34,18),
243 (35, 4),
244 (36,19),
245 (39,12),
246 (40,12),
247 (41,14),
248 (42,14),
249 (44,16),
250 (46,16)]);
251
252RBTab {
253 tp_receiver : tp_receiver,
254 rb_receiver : rb_receiver,
255 rb_selector : 0,
256 rb_changed : false,
257 rb_calibration : RBCalibrations::new(0),
258 cali_loaded : false,
259 event_queue : VecDeque::<RBEvent>::with_capacity(queue_size),
260 moni_queue : RBMoniDataSeries::new(),
262 global_rates : global_rates,
263 met_queue : VecDeque::<f64>::with_capacity(queue_size),
264 met_queue_moni : HashMap::<u8, VecDeque<f64>>::new(),
265 ltb_moni_queue : LTBMoniDataSeries::new(),
266 met_queue_ltb_moni : HashMap::<u8, VecDeque<f64>>::new(),
267 pa_show_biases : false,
268 pa_moni_queue : PAMoniDataSeries::new(),
269 met_queue_pa_moni : HashMap::<u8, VecDeque<f64>>::new(),
270 fpgatmp_queue : VecDeque::<(f64,f64)>::with_capacity(queue_size),
271 fpgatmp_fr_moni : true,
272
273 ch_data : ch_data,
274
275 queue_size : queue_size,
276
277 n_events : 0,
278 n_moni : 0,
279 miss_evid : 0,
280 last_evid : 0,
281 nch_histo : ndhistogram!(bins),
282 timer : Instant::now(),
283
284 theme : theme,
285 view : RBTabView::Waveform,
286
287 rbs : rbs,
288
289 list_focus : RBLTBListFocus::RBList,
290
291 rbl_state : rbl_state,
292 rbl_items : rb_select_items,
293 rbl_active : false,
294
295 rb_to_rat : rb_to_rat,
296 alerts : alerts,
297 alerts_active : alerts_active,
298 moni_old_check : moni_old_check,
299 }
300 }
301
302 pub fn receive_packet(&mut self) -> Result<(), SerializationError> {
303 let met = self.timer.elapsed().as_secs_f64();
304 let mut ev = RBEvent::new();
305 let bins = Uniform::new(50,-0.5,49.5).unwrap();
306 if self.rb_changed {
308 debug!("RB change detectod!");
309 self.event_queue.clear();
312 self.met_queue.clear();
313 self.fpgatmp_queue.clear();
315 self.nch_histo = ndhistogram!(bins);
316 match self.rbl_state.selected() {
318 None => {
319 self.cali_loaded = false;
320 },
321 Some(_rb_id) => {
322 let cali_path = format!("calibrations/RB{:02}.cali.tof.gaps", _rb_id + 1);
323 if fs::metadata(cali_path.clone()).is_ok() {
324 match RBCalibrations::from_file(cali_path.clone(), true) {
325 Err(err) => error!("Unable to load RBCalibration from file {}! {err}", cali_path),
326 Ok(cali) => {
327 self.rb_calibration = cali;
328 self.cali_loaded = true;
329 }
330 }
331 } else {
332 self.cali_loaded = false;
333 }
334 }
335 }
336 self.rb_changed = false;
337 info!("RB changed!");
338 }
339
340 for k in self.moni_old_check.keys() {
342 let moni_age = self.moni_old_check.get(&k).unwrap().elapsed().as_secs();
343 let alert_key_old = format!("rb{:02}_hk_too_old", k);
345 match self.alerts.lock() {
346 Ok(mut al) => {
347 match al.get_mut(alert_key_old.as_str() ) {
349 None => (),
350 Some(rb_moni_old_alert) => {
351 rb_moni_old_alert.trigger(moni_age as f32);
352 }
353 }
354 },
355 Err(err) => error!("Unable to lock global alerts! {err}"),
356 }
357 }
358
359 if !self.rb_receiver.is_empty() {
360 match self.rb_receiver.try_recv() {
361 Err(_) => (),
362 Ok(_ev) => {
363 ev = _ev;
364 }
365 }
366 }
367 if !self.tp_receiver.is_empty() {
368 match self.tp_receiver.try_recv() {
369 Err(_err) => (),
370 Ok(pack) => {
371 debug!("Got next packet {}!", pack);
372 match pack.packet_type {
373 PacketType::PAMoniData => {
374 info!("Received new PAMoniData!");
375 let moni : PAMoniData = pack.unpack()?;
376 self.pa_moni_queue.add(moni);
377 if !self.met_queue_pa_moni.contains_key(&moni.board_id) {
378 self.met_queue_pa_moni.insert(moni.board_id, VecDeque::<f64>::with_capacity(1000));
379 } else {
380 self.met_queue_pa_moni.get_mut(&moni.board_id).unwrap().push_back(met);
381 if self.met_queue_pa_moni.get(&moni.board_id).unwrap().len() > self.queue_size {
382 self.met_queue_pa_moni.get_mut(&moni.board_id).unwrap().pop_front();
383 }
384 }
385 return Ok(());
386 }
387 PacketType::LTBMoniData => {
388 trace!("Received new LTBMoniData!");
389 let moni : LTBMoniData = pack.unpack()?;
390 self.ltb_moni_queue.add(moni);
391 if !self.met_queue_ltb_moni.contains_key(&moni.board_id) {
392 self.met_queue_ltb_moni.insert(moni.board_id, VecDeque::<f64>::with_capacity(1000));
393 } else {
394 self.met_queue_ltb_moni.get_mut(&moni.board_id).unwrap().push_back(met);
395 if self.met_queue_ltb_moni.get(&moni.board_id).unwrap().len() > self.queue_size {
396 self.met_queue_ltb_moni.get_mut(&moni.board_id).unwrap().pop_front();
397 }
398 }
399 return Ok(());
400 },
401 PacketType::RBMoniData => {
402 trace!("Received new RBMoniData!");
403 let moni : RBMoniData = pack.unpack()?;
404 *self.moni_old_check.get_mut(&moni.board_id).unwrap() = Instant::now();
406 if self.alerts_active {
407 let alert_key_rate = format!("rb{:02}_rate_zero", moni.board_id);
413 let alert_key_temp = format!("rb{:02}_temp", moni.board_id);
414 match self.alerts.lock() {
417 Ok(mut al) => {
418 al.get_mut(alert_key_rate.as_str()).unwrap().trigger(moni.rate as f32);
420 al.get_mut(alert_key_temp.as_str()).unwrap().trigger(moni.tmp_drs);
421 },
423 Err(err) => error!("Unable to lock global alerts! {err}"),
424 }
425 }
426
427 self.moni_queue.add(moni);
428 self.n_moni += 1;
429 self.global_rates.insert(moni.board_id, format!("{}",moni.rate));
431
432 if !self.met_queue_moni.contains_key(&moni.board_id) {
433 self.met_queue_moni.insert(moni.board_id, VecDeque::<f64>::with_capacity(1000));
435 } else {
436 self.met_queue_moni.get_mut(&moni.board_id).unwrap().push_back(met);
437 if self.met_queue_moni.get(&moni.board_id).unwrap().len() > self.queue_size {
438 self.met_queue_moni.get_mut(&moni.board_id).unwrap().pop_front();
439 }
440 }
441 return Ok(());
442 },
443 PacketType::RBEvent => {
444 ev = pack.unpack()?;
445 },
446 PacketType::RBEventMemoryView => {
447 let mut streamer = RBEventMemoryStreamer::new();
448 streamer.add(&pack.payload, pack.payload.len());
450 match streamer.get_event_at_pos_unchecked(None) {
451 None => {
452 error!("Not able to obtain RBEvent from RBEventMemoryView packet!");
453 return Ok(());
454 }
455 Some(_ev) => {
456 ev = _ev;
457 }
458 }
459 },
460 _ => (),
461 }
462 }
463 }
464 }
465
466 if ev.header.event_id != 0 && self.rb_selector == ev.header.rb_id {
467 for ch in ev.header.get_channels() {
468 if self.cali_loaded {
469 let mut nanos = vec![0f32;1024];
470 let mut volts = vec![0f32;1024];
471 self.rb_calibration.nanoseconds(ch as usize + 1, ev.header.stop_cell as usize,
472 &mut nanos);
473 self.rb_calibration.voltages(ch as usize + 1, ev.header.stop_cell as usize,
474 &ev.adc[ch as usize], &mut volts);
475 for k in 0..nanos.len() {
477 let vals = (nanos[k] as f64, volts[k] as f64);
478 self.ch_data[ch as usize][k] = vals;
479 }
480 } else {
481 for k in 0..ev.adc[ch as usize].len() {
482 let vals = (k as f64, ev.adc[ch as usize][k] as f64);
483 self.ch_data[ch as usize][k] = vals;
484 }
485 }
487 }
488
489 self.nch_histo.fill(&(ev.header.get_nchan() as f32));
490 self.n_events += 1;
491 if self.last_evid != 0 {
492 if ev.header.event_id - self.last_evid != 1 {
493 self.miss_evid += (ev.header.event_id - self.last_evid) as usize;
494 }
495 }
496 self.last_evid = ev.header.event_id;
497 self.fpgatmp_queue.push_back((met, ev.header.get_fpga_temp() as f64));
498 self.fpgatmp_fr_moni = false; if self.fpgatmp_queue.len() > self.queue_size {
500 self.fpgatmp_queue.pop_front();
501 }
502 self.event_queue.push_back(ev);
503 if self.event_queue.len() > self.queue_size {
504 self.event_queue.pop_front();
505 }
506 self.met_queue.push_back(met);
507 if self.met_queue.len() > self.queue_size {
508 self.met_queue.pop_front();
509 }
510 }
511 Ok(())
512 }
513
514 pub fn next_rb(&mut self) {
515 let i = match self.rbl_state.selected() {
516 Some(i) => {
517 if i >= self.rbl_items.len() - 1 {
518 self.rbl_items.len() - 1
519 } else {
520 i + 1
521 }
522 }
523 None => 0,
524 };
525 self.rbl_state.select(Some(i));
526 }
528
529 pub fn previous_rb(&mut self) {
530 let i = match self.rbl_state.selected() {
531 Some(i) => {
532 if i == 0 {
533 0
534 } else {
535 i - 1
536 }
537 }
538 None => 0,
539 };
540 self.rbl_state.select(Some(i));
541 }
542
543 pub fn unselect_rbl(&mut self) {
544 self.rbl_state.select(None);
545 }
546
547
548 pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
549 match self.view {
550 RBTabView::SelectRB => {
551 let main_lo = Layout::default()
552 .direction(Direction::Horizontal)
553 .constraints(
554 [Constraint::Percentage(10),
555 Constraint::Percentage(90)].as_ref(),
557 )
558 .split(*main_window);
559 let rbs = Block::default()
560 .borders(Borders::ALL)
561 .style(self.theme.style())
562 .title("Select ReadoutBoard (RB)")
563 .border_type(BorderType::Plain);
564 let rb_select_list = List::new(self.rbl_items.clone()).block(rbs)
565 .highlight_style(self.theme.highlight().add_modifier(Modifier::BOLD))
566 .highlight_symbol(">>")
567 .repeat_highlight_symbol(true);
568 match self.list_focus {
569 RBLTBListFocus::RBList => {
570 match self.rbl_state.selected() {
571 None => {
572 let selector = 1;
573 if self.rb_selector != selector {
574 self.rb_changed = true;
575 self.rb_selector = selector;
576 } else {
577 self.rb_changed = false;
578 }
579 },
580 Some(_rbid) => {
581 let selector = _rbid as u8 + 1;
582 if self.rb_selector != selector {
583 self.rb_changed = true;
584 self.rb_selector = selector;
585 } else {
586 self.rb_changed = false;
587 }
588 },
589 }
590 },
591 _ => ()
592 }
593 let view_string : String;
594 match self.rbs.get(&self.rb_selector) {
595 Some(_rb) => {
596 view_string = format!("{}", _rb.to_summary_str());
597 }
598 None => {
599 view_string = format!("No information for RB {} in DB \n or DB not available!", self.rb_selector);
600 }
601 }
602 let rb_view = Paragraph::new(view_string)
603 .style(self.theme.style())
604 .alignment(Alignment::Left)
605 .block(
607 Block::default()
608 .borders(Borders::ALL)
609 .style(self.theme.style())
610 .title("RB")
611 .border_type(BorderType::Rounded),
612 );
613
614 frame.render_stateful_widget(rb_select_list, main_lo[0], &mut self.rbl_state );
615 frame.render_widget(rb_view, main_lo[1]);
616 },
617 RBTabView::Waveform => {
618 let status_chunks = Layout::default()
620 .direction(Direction::Horizontal)
621 .constraints(
622 [Constraint::Percentage(30), Constraint::Percentage(70)].as_ref(),
623 )
624 .split(*main_window);
625
626 let detail_and_ch9_chunks = Layout::default()
627 .direction(Direction::Vertical)
628 .constraints(
629 [Constraint::Percentage(25),
630 Constraint::Percentage(75)].as_ref(),
631 )
632 .split(status_chunks[0]);
633
634 let wf_chunks = Layout::default()
635 .direction(Direction::Horizontal)
636 .constraints(
637 [Constraint::Percentage(50),
638 Constraint::Percentage(50)].as_ref(),
639 )
640 .split(status_chunks[1]);
641
642 let mut ch_chunks = Layout::default()
643 .direction(Direction::Vertical)
644 .constraints(
645 [Constraint::Percentage(25),
646 Constraint::Percentage(25),
647 Constraint::Percentage(26),
648 Constraint::Percentage(25)].as_ref(),
649 )
650 .split(wf_chunks[0]).to_vec();
651
652 let mut ch_chunks_2 = Layout::default()
653 .direction(Direction::Vertical)
654 .constraints(
655 [Constraint::Percentage(25),
656 Constraint::Percentage(25),
657 Constraint::Percentage(26),
658 Constraint::Percentage(25)].as_ref(),
659 )
660 .split(wf_chunks[1]).to_vec();
661
662 ch_chunks.append(&mut ch_chunks_2);
663 for ch in 0..9 {
665 let label = format!("Ch{}", ch + 1);
666 let ch_tc_theme = self.theme.clone();
667 let mut ch_ts_data = VecDeque::from(self.ch_data[ch].clone());
668 let ch_ts = timeseries(&mut ch_ts_data,
669 label.clone(),
670 label.clone(),
671 &ch_tc_theme );
672 if ch == 8 {
674 frame.render_widget(ch_ts,detail_and_ch9_chunks[0]);
676 } else {
677 frame.render_widget(ch_ts,ch_chunks[ch]);
678 }
680 } let last_event = self.event_queue.back();
684 let view_string : String;
685 match last_event {
686 Some(event) => {
687 view_string = event.to_string();
688 },
689 None => {
690 view_string = String::from("EVT QUEUE EMPTY!");
691 }
692 }
693 let event_view = Paragraph::new(view_string)
694 .style(self.theme.style())
695 .alignment(Alignment::Left)
696 .block(
698 Block::default()
699 .borders(Borders::ALL)
700 .style(self.theme.style())
701 .title("Last RBEvent")
702 .border_type(BorderType::Rounded),
703 );
704 frame.render_widget(event_view, detail_and_ch9_chunks[1]);
705 } RBTabView::RBMoniData => {
707 let columns = Layout::default()
710 .direction(Direction::Horizontal)
711 .constraints(
712 [Constraint::Percentage(25),
713 Constraint::Percentage(25),
714 Constraint::Percentage(25),
715 Constraint::Percentage(25),
716 ].as_ref(),
717 )
718 .split(*main_window);
719 let col0 = Layout::default()
720 .direction(Direction::Vertical)
721 .constraints(
722 [Constraint::Percentage(75),
723 Constraint::Percentage(25)].as_ref()
724 )
725 .split(columns[0]);
726 let col1 = Layout::default()
727 .direction(Direction::Vertical)
728 .constraints(
729 [Constraint::Percentage(25),
730 Constraint::Percentage(25),
731 Constraint::Percentage(25),
732 Constraint::Percentage(25),
733 ].as_ref(),
734 )
735 .split(columns[1]);
736 let col2 = Layout::default()
737 .direction(Direction::Vertical)
738 .constraints(
739 [Constraint::Percentage(25),
740 Constraint::Percentage(25),
741 Constraint::Percentage(25),
742 Constraint::Percentage(25),
743 ].as_ref(),
744 )
745 .split(columns[2]);
746 let col3 = Layout::default()
747 .direction(Direction::Vertical)
748 .constraints(
749 [Constraint::Percentage(25),
750 Constraint::Percentage(25),
751 Constraint::Percentage(25),
752 Constraint::Percentage(25),
753 ].as_ref(),
754 )
755 .split(columns[3]);
756
757 let last_moni = self.moni_queue.get_last_moni(self.rb_selector);
758 let view_string : String;
759 match last_moni {
760 Some(_moni) => {
761 view_string = _moni.to_string();
762 },
763 None => {
764 view_string = format!("No RBMoniData for board {} avaiable", self.rb_selector);
765 }
766 }
767
768 let moni_view = Paragraph::new(view_string)
769 .style(self.theme.style())
770 .alignment(Alignment::Left)
771 .block(
773 Block::default()
774 .borders(Borders::ALL)
775 .style(self.theme.style())
776 .title("Last RBMoniData")
777 .border_type(BorderType::Rounded),
778 );
779 frame.render_widget(moni_view, col0[0]);
780
781 let rate_ds_name = String::from("Rate");
782 let rate_ds_title = String::from("RB Rate [Hz]");
783 let rate_data = self.moni_queue.get_var_for_board("rate", &self.rb_selector);
784 let mut rate_ts = VecDeque::<(f64, f64)>::new();
785 match rate_data {
786 None => {
787 error!("No rate data available for board {}", self.rb_selector);
788 },
789 Some(rdata) => {
790 if rdata.len() != 0 {
791 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
792 rate_ts.push_back((*time, rdata[k] as f64));
793 }
794 }
795 }
796 }
797 let rate_tc = timeseries(&mut rate_ts,
798 rate_ds_name,
799 rate_ds_title,
800 &self.theme);
801 frame.render_widget(rate_tc, col0[1]);
802
803 let mag_tot_ds_name = String::from("Magnetic Field");
805 let mag_tot_ds_title = String::from("Tot mag field [Gauss]");
806 let mag_tot_data = self.moni_queue.get_var_for_board("mag_tot", &self.rb_selector);
807 let mut mag_tot_ts = VecDeque::<(f64, f64)>::new();
808 match mag_tot_data {
809 None => {
810 error!("No mag_tot data available for board {}", self.rb_selector);
811 },
812 Some(data) => {
813 if data.len() != 0 {
814 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
815 mag_tot_ts.push_back((*time, data[k] as f64));
816 }
817 }
818 }
819 }
820 let mag_tot_tc = timeseries(&mut mag_tot_ts,
821 mag_tot_ds_name,
822 mag_tot_ds_title,
823 &self.theme);
824 frame.render_widget(mag_tot_tc, col1[0]);
825
826 let pres_ds_name = String::from("Atmospheric pressure");
827 let pres_ds_title = String::from("Atmospheric pressure [hPa]");
828 let pres_data = self.moni_queue.get_var_for_board("pressure", &self.rb_selector);
829 let mut pres_ts = VecDeque::<(f64, f64)>::new();
830 match pres_data {
831 None => {
832 error!("No atmos pressure data available for board {}", self.rb_selector);
833 },
834 Some(data) => {
835 if data.len() != 0 {
836 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
837 pres_ts.push_back((*time, data[k] as f64));
838 }
839 }
840 }
841 }
842
843 let pres_tc = timeseries(&mut pres_ts,
844 pres_ds_name,
845 pres_ds_title,
846 &self.theme);
847 frame.render_widget(pres_tc, col1[1]);
848
849 let humi_ds_name = String::from("Ambient humidity");
850 let humi_ds_title = String::from("Humidity [%]");
851 let humi_data = self.moni_queue.get_var_for_board("humidity", &self.rb_selector);
852 let mut humi_ts = VecDeque::<(f64, f64)>::new();
853 match humi_data {
854 None => {
855 error!("No humidity data available for board {}", self.rb_selector);
856 },
857 Some(data) => {
858 if data.len() != 0 {
859 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
860 humi_ts.push_back((*time, data[k] as f64));
861 }
862 }
863 }
864 }
865 let humi_tc = timeseries(&mut humi_ts,
866 humi_ds_name,
867 humi_ds_title,
868 &self.theme);
869 frame.render_widget(humi_tc, col1[2]);
870
871 let fpga_ds_name = String::from("FPGA (DRS) Temperature");
873 let fpga_ds_title = String::from("DRS Temp [\u{00B0}C]");
874 if !self.fpgatmp_fr_moni {
877 let fpga_tc = timeseries(&mut self.fpgatmp_queue,
878 fpga_ds_name,
879 fpga_ds_title,
880 &self.theme );
881 frame.render_widget(fpga_tc, col1[3]);
882 } else {
883 let fpga_data = self.moni_queue.get_var_for_board("tmp_drs", &self.rb_selector);
885 let mut fpga_ts = VecDeque::<(f64, f64)>::new();
886 match fpga_data {
887 None => {
888 error!("No DRS4 temperature data available for board {}", self.rb_selector);
889 },
890 Some(data) => {
891 if data.len() != 0 {
892 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
893 fpga_ts.push_back((*time, data[k] as f64));
894 }
895 }
896 }
897 }
898 let fpga_tc = timeseries(&mut fpga_ts,
899 fpga_ds_name,
900 fpga_ds_title,
901 &self.theme);
902 frame.render_widget(fpga_tc, col1[3]);
903 }
904
905 let tmp_clk_ds_name = String::from("CLK Temperature");
906 let tmp_clk_ds_title = String::from("CLK Temp. [\u{00B0}C]");
907 let tmp_clk_data = self.moni_queue.get_var_for_board("tmp_clk", &self.rb_selector);
908 let mut tmp_clk_ts = VecDeque::<(f64, f64)>::new();
909 match tmp_clk_data {
910 None => {
911 error!("No CLK temperature data available for board {}", self.rb_selector);
912 },
913 Some(data) => {
914 if data.len() != 0 {
915 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
916 tmp_clk_ts.push_back((*time, data[k] as f64));
917 }
918 }
919 }
920 }
921 let tmp_clk_tc = timeseries(&mut tmp_clk_ts,
922 tmp_clk_ds_name,
923 tmp_clk_ds_title,
924 &self.theme);
925 frame.render_widget(tmp_clk_tc, col2[0]);
926
927 let tmp_adc_ds_name = String::from("ADC Temperature");
928 let tmp_adc_ds_title = String::from("ADC Temp. [\u{00B0}C]");
929 let tmp_adc_data = self.moni_queue.get_var_for_board("tmp_adc", &self.rb_selector);
930 let mut tmp_adc_ts = VecDeque::<(f64, f64)>::new();
931 match tmp_adc_data {
932 None => {
933 error!("No ADC temperature data available for board {}", self.rb_selector);
934 },
935 Some(data) => {
936 if data.len() != 0 {
937 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
938 tmp_adc_ts.push_back((*time, data[k] as f64));
939 }
940 }
941 }
942 }
943 let tmp_adc_tc = timeseries(&mut tmp_adc_ts,
944 tmp_adc_ds_name,
945 tmp_adc_ds_title,
946 &self.theme);
947 frame.render_widget(tmp_adc_tc, col2[1]);
948
949 let tmp_zynq_ds_name = String::from("ZYNQ Temperature");
950 let tmp_zynq_ds_title = String::from("ZYNQ Temp. [\u{00B0}C]");
951 let tmp_zynq_data = self.moni_queue.get_var_for_board("tmp_zynq", &self.rb_selector);
952 let mut tmp_zynq_ts = VecDeque::<(f64, f64)>::new();
953 match tmp_zynq_data {
954 None => {
955 error!("No ZYNQ temperature data available for board {}", self.rb_selector);
956 },
957 Some(data) => {
958 if data.len() != 0 {
959 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
960 tmp_zynq_ts.push_back((*time, data[k] as f64));
961 }
962 }
963 }
964 }
965 let tmp_zynq_tc = timeseries(&mut tmp_zynq_ts,
966 tmp_zynq_ds_name,
967 tmp_zynq_ds_title,
968 &self.theme);
969 frame.render_widget(tmp_zynq_tc, col2[2]);
970
971 let tmp_bm280_name = String::from("BM280 Temperature");
972 let tmp_bm280_title = String::from("BM280 Temp. [\u{00B0}C]");
973 let tmp_bm280_data = self.moni_queue.get_var_for_board("tmp_bm280", &self.rb_selector);
974 let mut tmp_bm280_ts = VecDeque::<(f64, f64)>::new();
975 match tmp_bm280_data {
976 None => {
977 error!("No BM280 temperature data available for board {}", self.rb_selector);
978 },
979 Some(data) => {
980 if data.len() != 0 {
981 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
982 tmp_bm280_ts.push_back((*time, data[k] as f64));
983 }
984 }
985 }
986 }
987 let tmp_bm280_tc = timeseries(&mut tmp_bm280_ts,
988 tmp_bm280_name,
989 tmp_bm280_title,
990 &self.theme);
991 frame.render_widget(tmp_bm280_tc, col2[3]);
992
993 let drs_c_name = String::from("DRS Current");
995 let drs_c_title = String::from("DRS Curr. [mA]");
996 let drs_c_data = self.moni_queue.get_var_for_board("drs_dvdd_current", &self.rb_selector);
997 let mut drs_c_ts = VecDeque::<(f64, f64)>::new();
998 match drs_c_data {
999 None => {
1000 error!("No DRS4 current data available for board {}", self.rb_selector);
1001 },
1002 Some(data) => {
1003 if data.len() != 0 {
1004 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1005 drs_c_ts.push_back((*time, data[k] as f64));
1006 }
1007 }
1008 }
1009 }
1010 let drs_c_tc = timeseries(&mut drs_c_ts,
1011 drs_c_name,
1012 drs_c_title,
1013 &self.theme);
1014 frame.render_widget(drs_c_tc, col3[0]);
1015
1016 let zynq_c_name = String::from("Zynq Current");
1017 let zynq_c_title = String::from("Zynq Curr. [mA]");
1018 let zynq_c_data = self.moni_queue.get_var_for_board("zynq_current", &self.rb_selector);
1019 let mut zynq_c_ts = VecDeque::<(f64, f64)>::new();
1020 match zynq_c_data {
1021 None => {
1022 error!("No ZYNQ current data available for board {}", self.rb_selector);
1023 },
1024 Some(data) => {
1025 if data.len() != 0 {
1026 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1027 zynq_c_ts.push_back((*time, data[k] as f64));
1028 }
1029 }
1030 }
1031 }
1032 let zynq_c_tc = timeseries(&mut zynq_c_ts,
1033 zynq_c_name,
1034 zynq_c_title,
1035 &self.theme);
1036 frame.render_widget(zynq_c_tc, col3[1]);
1037
1038 let p3v3_c_name = String::from("P3V3 Current");
1039 let p3v3_c_title = String::from("P3V3 Curr. [mA]");
1040 let p3v3_c_data = self.moni_queue.get_var_for_board("p3v3_current", &self.rb_selector);
1041 let mut p3v3_c_ts = VecDeque::<(f64, f64)>::new();
1042 match p3v3_c_data {
1043 None => {
1044 error!("No P3V3 current data available for board {}", self.rb_selector);
1045 },
1046 Some(data) => {
1047 if data.len() != 0 {
1048 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1049 p3v3_c_ts.push_back((*time, data[k] as f64));
1050 }
1051 }
1052 }
1053 }
1054 let p3v3_c_tc = timeseries(&mut p3v3_c_ts,
1055 p3v3_c_name,
1056 p3v3_c_title,
1057 &self.theme);
1058 frame.render_widget(p3v3_c_tc, col3[2]);
1059
1060 let p3v5_c_name = String::from("P3V5 Current");
1061 let p3v5_c_title = String::from("P3V5 Curr. [mA]");
1062 let p3v5_c_data = self.moni_queue.get_var_for_board("p3v5_current", &self.rb_selector);
1063 let mut p3v5_c_ts = VecDeque::<(f64, f64)>::new();
1064 match p3v5_c_data {
1065 None => {
1066 error!("No P3V5 current data available for board {}", self.rb_selector);
1067 },
1068 Some(data) => {
1069 if data.len() != 0 {
1070 for (k, time) in self.met_queue_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1071 p3v5_c_ts.push_back((*time, data[k] as f64));
1072 }
1073 }
1074 }
1075 }
1076 let p3v5_c_tc = timeseries(&mut p3v5_c_ts,
1077 p3v5_c_name,
1078 p3v5_c_title,
1079 &self.theme);
1080 frame.render_widget(p3v5_c_tc, col3[3]);
1081 },
1082 RBTabView::LTBMoniData => {
1083 let columns = Layout::default()
1084 .direction(Direction::Horizontal)
1085 .constraints(
1086 [Constraint::Percentage(30),
1087 Constraint::Percentage(70)].as_ref(),
1088 )
1089 .split(*main_window);
1090 let rows = Layout::default()
1091 .direction(Direction::Vertical)
1092 .constraints(
1093 [Constraint::Percentage(30),
1094 Constraint::Percentage(30),
1095 Constraint::Percentage(40)].as_ref(),
1096 )
1097 .split(columns[1]);
1098
1099 let last_ltb_moni = self.ltb_moni_queue.get_last_moni(self.rb_selector);
1100 let mut ltb_moni_str = format!("No data for board {}!", self.rb_selector);
1101 let mut ltb_thr_str = format!("No data for board {}!", self.rb_selector);
1102 match last_ltb_moni {
1103 None => (),
1104 Some(mon) => {
1105 ltb_moni_str = format!("{}", mon);
1106 ltb_thr_str = format!(" Hit : {:.3} [mV]", mon.thresh[0]);
1107 ltb_thr_str += &(format!("\n Beta : {:.3} [mV]", mon.thresh[1]));
1108 ltb_thr_str += &(format!("\n Veto : {:.3} [mV]", mon.thresh[2]));
1109 }
1110 }
1111 let moni_view = Paragraph::new(ltb_moni_str)
1112 .style(self.theme.style())
1113 .alignment(Alignment::Left)
1114 .block(
1116 Block::default()
1117 .borders(Borders::ALL)
1118 .style(self.theme.style())
1119 .title("Last LTBMoniData")
1120 .border_type(BorderType::Rounded),
1121 );
1122 frame.render_widget(moni_view, columns[0]);
1123 let thr_view = Paragraph::new(ltb_thr_str)
1124 .style(self.theme.style())
1125 .alignment(Alignment::Left)
1126 .block(
1128 Block::default()
1129 .borders(Borders::ALL)
1130 .style(self.theme.style())
1131 .title("Thresholds")
1132 .border_type(BorderType::Rounded),
1133 );
1134 frame.render_widget(thr_view, rows[2]);
1135
1136 let tt_name = String::from("Trenz Temp");
1137 let tt_title = String::from("Trenz Temp [\u{00B0}C]");
1138 let tt_data = self.ltb_moni_queue.get_var_for_board("trenz_temp", &self.rb_selector);
1139 let mut tt_ts = VecDeque::<(f64, f64)>::new();
1140 match tt_data {
1141 None => {
1142 error!("No trenz temp data available for board {}", self.rb_selector);
1143 },
1144 Some(data) => {
1145 if data.len() != 0 {
1146 for (k, time) in self.met_queue_ltb_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1147 tt_ts.push_back((*time, data[k] as f64));
1148 }
1149 }
1150 }
1151 }
1152 let tt_tc = timeseries(&mut tt_ts,
1153 tt_name,
1154 tt_title,
1155 &self.theme);
1156 frame.render_widget(tt_tc, rows[0]);
1157
1158 let lt_name = String::from("LTB Temperature");
1159 let lt_title = String::from("LTB Temp. [\u{00B0}C]");
1160 let lt_data = self.ltb_moni_queue.get_var_for_board("ltb_temp", &self.rb_selector);
1161 let mut lt_ts = VecDeque::<(f64, f64)>::new();
1162 match lt_data {
1163 None => {
1164 error!("No LTB temp data available for board {}", self.rb_selector);
1165 },
1166 Some(data) => {
1167 if data.len() != 0 {
1168 for (k, time) in self.met_queue_ltb_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1169 lt_ts.push_back((*time, data[k] as f64));
1170 }
1171 }
1172 }
1173 }
1174 let lt_tc = timeseries(&mut lt_ts,
1175 lt_name,
1176 lt_title,
1177 &self.theme);
1178 frame.render_widget(lt_tc, rows[1]);
1179
1180 }
1181 RBTabView::PAMoniData => {
1182 let rows = Layout::default()
1183 .direction(Direction::Vertical)
1184 .constraints(
1185 [Constraint::Percentage(8),
1186 Constraint::Percentage(92)].as_ref(),
1187 )
1188 .split(*main_window);
1189 let columns = Layout::default()
1190 .direction(Direction::Horizontal)
1191 .constraints(
1192 [Constraint::Percentage(25),
1193 Constraint::Percentage(25),
1194 Constraint::Percentage(25),
1195 Constraint::Percentage(25)].as_ref(),
1196 )
1197 .split(rows[1]);
1198 let col0 = Layout::default()
1199 .direction(Direction::Vertical)
1200 .constraints(
1201 [Constraint::Percentage(24),
1202 Constraint::Percentage(24),
1203 Constraint::Percentage(24),
1204 Constraint::Percentage(24)].as_ref(),
1205 )
1206 .split(columns[0]);
1207 let col1 = Layout::default()
1208 .direction(Direction::Vertical)
1209 .constraints(
1210 [Constraint::Percentage(24),
1211 Constraint::Percentage(24),
1212 Constraint::Percentage(24),
1213 Constraint::Percentage(24)].as_ref(),
1214 )
1215 .split(columns[1]);
1216 let col2 = Layout::default()
1217 .direction(Direction::Vertical)
1218 .constraints(
1219 [Constraint::Percentage(24),
1220 Constraint::Percentage(24),
1221 Constraint::Percentage(24),
1222 Constraint::Percentage(24)].as_ref(),
1223 )
1224 .split(columns[2]);
1225 let col3 = Layout::default()
1226 .direction(Direction::Vertical)
1227 .constraints(
1228 [Constraint::Percentage(24),
1229 Constraint::Percentage(24),
1230 Constraint::Percentage(24),
1231 Constraint::Percentage(24)].as_ref(),
1232 )
1233 .split(columns[3]);
1234 let pa_str = format!("PreampMoniData for ReadoutBoard {}", self.rb_selector);
1236 let pa_view = Paragraph::new(pa_str)
1237 .style(self.theme.style())
1238 .alignment(Alignment::Left)
1239 .block(
1240 Block::default()
1241 .borders(Borders::ALL)
1242 .style(self.theme.style())
1243 .border_type(BorderType::Rounded),
1245 );
1246 frame.render_widget(pa_view, rows[0]);
1247
1248 if self.pa_show_biases {
1249 for k in 0..16 {
1269 let identifier = format!("bias_{}", k+1);
1270 let name = format!("Ch {} Bias Voltage", k+1);
1271 let title = format!("Ch {} Bias [V]", k+1);
1272 let c_data = self.pa_moni_queue.get_var_for_board(&identifier, &self.rb_selector);
1273 let mut ts = VecDeque::<(f64, f64)>::new();
1274 match c_data {
1275 None => {
1276 error!("No {} data available for board {}", identifier, self.rb_selector);
1277 },
1278 Some(data) => {
1279 for (k, time) in self.met_queue_pa_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1280 ts.push_back((*time, data[k] as f64));
1281 }
1282 }
1283 }
1284 let tc = timeseries(&mut ts,
1285 name,
1286 title,
1287 &self.theme);
1288 if k < 4 {
1289 frame.render_widget(tc, col0[k]);
1290 } else if k < 8 {
1291 frame.render_widget(tc, col1[k-4]);
1292 } else if k < 12 {
1293 frame.render_widget(tc, col2[k-8]);
1294 } else if k < 16 {
1295 frame.render_widget(tc, col3[k-12]);
1296 }
1297 }
1298 } else {
1299 for k in 0..16 {
1301 let identifier = format!("temps{}", k+1);
1302 let name = format!("Ch {} Temperature", k+1);
1303 let title = format!("Ch {} Temp [\u{00B0}C]", k+1);
1304 let c_data = self.pa_moni_queue.get_var_for_board(&identifier, &self.rb_selector);
1305 let mut ts = VecDeque::<(f64, f64)>::new();
1306 match c_data {
1307 None => {
1308 error!("No {} data available for board {}", identifier, self.rb_selector);
1309 },
1310 Some(data) => {
1311 if data.len() != 0 {
1312 for (k, time) in self.met_queue_pa_moni.get(&self.rb_selector).unwrap().iter().enumerate() {
1313 ts.push_back((*time, data[k] as f64));
1314 }
1315 }
1316 }
1317 }
1318 let tc = timeseries(&mut ts,
1319 name,
1320 title,
1321 &self.theme);
1322 if k < 4 {
1323 frame.render_widget(tc, col0[k]);
1324 } else if k < 8 {
1325 frame.render_widget(tc, col1[k-4]);
1326 } else if k < 12 {
1327 frame.render_widget(tc, col2[k-8]);
1328 } else if k < 16 {
1329 frame.render_widget(tc, col3[k-12]);
1330 }
1331 }
1332 }
1333 }
1334 RBTabView::PBMoniData => {
1335 }
1336 RBTabView::GlobalRates => {
1337 let mut rows = Vec::<Row>::new();
1339 let mut rbids = Vec::from_iter(&mut self.global_rates.keys());
1341 rbids.sort();
1342 let mut ncol = 0;
1343 let mut this_row = Vec::<String>::new();
1344 for k in rbids {
1345 this_row.push(format!("RB {:02}", k));
1346 if self.global_rates[k] == String::from("0") {
1347 this_row.push(format!("\u{203c} {} Hz", self.global_rates[k]));
1348 } else {
1349 this_row.push(format!("\u{2714} {} Hz", self.global_rates[k]));
1350 }
1351 ncol += 2;
1352 if ncol == 8 {
1353 rows.push(Row::new(this_row.clone()));
1354 this_row = Vec::<String>::new();
1355 ncol = 0;
1356 }
1357 }
1360 let widths = [
1362 Constraint::Percentage(12),
1363 Constraint::Percentage(12),
1364 Constraint::Percentage(12),
1365 Constraint::Percentage(12),
1366 Constraint::Percentage(12),
1367 Constraint::Percentage(12),
1368 Constraint::Percentage(12),
1369 Constraint::Percentage(16),
1370 ];
1371 let table = Table::new(rows, widths)
1372 .column_spacing(1)
1374 .style(Style::new().blue())
1376 .header(
1378 Row::new(vec!["RBs", "Rate", "RBs", "Rate", "RBs", "Rate", "RBs", "Rate"])
1379 .style(self.theme.style())
1380 .bottom_margin(1),
1382 )
1383 .block(
1387 Block::default()
1388 .borders(Borders::ALL)
1389 .style(self.theme.style())
1390 .title("RB Trigger rates (scalar, from RBMoniData)")
1391 .border_type(BorderType::Rounded),
1392 )
1393 .row_highlight_style(self.theme.style())
1395 .column_highlight_style(self.theme.style())
1396 .cell_highlight_style(self.theme.style());
1397 frame.render_widget(table, *main_window);
1400 }
1401 RBTabView::Info => {
1403 let main_view = Layout::default()
1404 .direction(Direction::Horizontal)
1405 .constraints(
1406 [Constraint::Percentage(30), Constraint::Percentage(70)].as_ref(),
1407 )
1408 .split(*main_window);
1409 let view_info = format!("Summary Statistics:
1410 N_Events : {}
1411 N_Moni : {}
1412 N EventID Missed : {}",
1413 self.n_events,
1414 self.n_moni,
1415 self.miss_evid);
1416 let info_view = Paragraph::new(view_info)
1417 .style(self.theme.style())
1418 .alignment(Alignment::Left)
1419 .block(
1420 Block::default()
1421 .borders(Borders::ALL)
1422 .style(self.theme.style())
1423 .title("Overview")
1424 .border_type(BorderType::Rounded),
1425 );
1426
1427 frame.render_widget(info_view, main_view[0]);
1429 }
1430 } }
1432}
1433