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