liftof_tui/
lib.rs

1#[macro_use] extern crate log;
2
3pub mod menu;
4pub mod colors;
5pub mod widgets;
6pub mod tabs;
7pub mod layout;
8
9use std::sync::Mutex;
10use std::sync::Arc;
11
12use std::collections::HashMap;
13use std::collections::VecDeque;
14
15use tui_logger::TuiLoggerWidget;
16use ratatui::{
17  style::{
18    Color,
19    Style,
20  },
21  widgets::{
22    Block,
23    Borders,
24  },
25};
26
27pub use crate::tabs::*;
28pub use crate::layout::*;
29
30use crate::colors::ColorTheme;
31use gondola_core::prelude::*;
32
33//use tof_dataclasses::packets::TofPacket;
34//use tof_dataclasses::packets::PacketType;
35//use tof_dataclasses::events::MasterTriggerEvent;
36//use tof_dataclasses::events::TofEventSummary;
37//use tof_dataclasses::events::TofHit;
38//use tof_dataclasses::serialization::Packable;
39//use tof_dataclasses::serialization::Serialization;
40//use tof_dataclasses::io::TofPacketWriter;
41
42use crossbeam_channel::{
43  Sender,
44  Receiver
45};
46
47/// A map which keeps track of the types of telemetry packets 
48/// received
49pub fn telly_packet_counter(pack_map : &mut HashMap<&str, usize>, packet_type : &TelemetryPacketType) {
50  let pack_key : &str;
51  match packet_type {
52    TelemetryPacketType::Unknown            => pack_key = "Unknown",
53    TelemetryPacketType::CardHKP            => pack_key = "CardHKP",
54    TelemetryPacketType::CoolingHK          => pack_key = "CoolingHKP",
55    TelemetryPacketType::PDUHK              => pack_key = "PDUHK",
56    TelemetryPacketType::Tracker            => pack_key = "Tracker",
57    TelemetryPacketType::TrackerDAQCntr     => pack_key = "TrakcerDAQCntr",
58    TelemetryPacketType::GPS                => pack_key = "GPS",
59    TelemetryPacketType::TrkTempLeak        => pack_key = "TrkTempLeak",
60    TelemetryPacketType::BoringEvent        => pack_key = "BoringEvent",
61    TelemetryPacketType::RBWaveform         => pack_key = "RBWaveform",
62    TelemetryPacketType::AnyTofHK           => pack_key = "AnyTofHK",
63    TelemetryPacketType::GcuEvtBldSettings  => pack_key = "GcuEvtBldSettings",
64    TelemetryPacketType::LabJackHK          => pack_key = "LabJackHK",
65    TelemetryPacketType::MagHK              => pack_key = "MagHK",
66    TelemetryPacketType::GcuMon             => pack_key = "GcuMon",
67    TelemetryPacketType::InterestingEvent   => pack_key = "InterestingEvent",
68    TelemetryPacketType::NoGapsTriggerEvent => pack_key = "NoGapsTriggerEvent",
69    TelemetryPacketType::NoTofDataEvent     => pack_key = "NoTofDataEvent",
70    TelemetryPacketType::Ack                => pack_key = "Ack",     
71    TelemetryPacketType::AnyTrackerHK       => pack_key = "AnyTrackerHK",
72    TelemetryPacketType::TmP33              => pack_key = "TmP33",
73    TelemetryPacketType::TmP34              => pack_key = "TmP34",
74    TelemetryPacketType::TmP37              => pack_key = "TmP37",
75    TelemetryPacketType::TmP38              => pack_key = "TmP38",
76    TelemetryPacketType::TmP55              => pack_key = "TmP55",
77    TelemetryPacketType::TmP64              => pack_key = "TmP64",
78    TelemetryPacketType::TmP96              => pack_key = "TmP96",
79    TelemetryPacketType::TmP214             => pack_key = "TmP214",
80  //_                              => pack_key = "Unknown",
81  }
82  if pack_map.get(pack_key).is_some() {
83    *pack_map.get_mut(pack_key).unwrap() += 1;
84  } else {
85    pack_map.insert(pack_key, 0);
86  }
87}
88
89/// Use the TuiLoggerWidget to display 
90/// the most recent log messages
91///
92///
93pub fn render_logs<'a>(theme : ColorTheme) -> TuiLoggerWidget<'a> {
94  TuiLoggerWidget::default()
95    .style_error(Style::default().fg(Color::Red))
96    .style_debug(Style::default().fg(Color::Green))
97    .style_warn(Style::default().fg(Color::Yellow))
98    .style_trace(Style::default().fg(Color::Gray))
99    .style_info(Style::default().fg(Color::Blue))
100    .block(
101      Block::default()
102        .title("Logs")
103        .border_style(theme.style())
104        .borders(Borders::ALL),
105    )   
106    .style(theme.style())
107}
108
109/// Count the different types of tofpackets and store the result 
110/// in a HashMap
111///
112/// # Arguments:
113///
114///   * packet_type : TofPacket type to llokup it's position in 
115///                   the map
116///   * packet_map  : An arc/mutex to the HashMap we use to store
117///                   the counted values in.
118fn packet_sorter(packet_type : &TofPacketType,
119                 packet_map  : &Arc<Mutex<HashMap<&str,usize>>>) {
120  match packet_map.lock() {
121    Ok(mut pm) => {
122      let pack_key : &str;
123      //let pt = packet_type.cl
124      //let pt = packet_type.clone();
125      //let pack_key = pt.as_ref();
126      match packet_type {
127        TofPacketType::Unknown               => pack_key = "Unknown", 
128        TofPacketType::RBEvent               => pack_key = "RBEvent",
129        TofPacketType::TofEvent              => pack_key = "TofEvent",
130        TofPacketType::RBWaveform            => pack_key = "RBWaveform",
131        TofPacketType::TofEventDeprecated    => pack_key = "TofEventDeprecated",
132        TofPacketType::DataSinkHB            => pack_key = "DataSinkHB",    
133        TofPacketType::MasterTrigger         => pack_key = "MasterTrigger",
134        TofPacketType::TriggerConfig         => pack_key = "TriggerConfig",
135        TofPacketType::MasterTriggerHB       => pack_key = "MasterTriggerHHB", 
136        TofPacketType::EventBuilderHB        => pack_key = "EventBuilderHB",
137        TofPacketType::RBChannelMaskConfig   => pack_key = "RBChannelMaskConfig",
138        TofPacketType::TofRBConfig           => pack_key = "TofRBConfig",
139        TofPacketType::AnalysisEngineConfig  => pack_key = "AnalysisEngineConfig",
140        TofPacketType::RBEventHeader         => pack_key = "RBEventHeader",    // needs to go away
141        TofPacketType::TOFEventBuilderConfig => pack_key = "TOFEventBuilderConfig",
142        TofPacketType::DataPublisherConfig   => pack_key = "DataPublisherConfig",
143        TofPacketType::TofRunConfig          => pack_key = "TofRunConfig",
144        TofPacketType::CPUMoniData           => pack_key = "CPUMoniData",
145        TofPacketType::MtbMoniData           => pack_key = "MtbMoniData",
146        TofPacketType::RBMoniData            => pack_key = "RBMoniData",
147        TofPacketType::PBMoniData            => pack_key = "PBMoniData",
148        TofPacketType::LTBMoniData           => pack_key = "LTBMoniData",
149        TofPacketType::PAMoniData            => pack_key = "PAMoniData",
150        TofPacketType::RBEventMemoryView     => pack_key = "RBEventMemoryView", // We'll keep it for now - indicates that the event
151        TofPacketType::RBCalibration         => pack_key = "RBCalibration",
152        TofPacketType::TofCommand            => pack_key = "TofCommand",
153        TofPacketType::TofCommandV2          => pack_key = "TofCommandV2",
154        TofPacketType::TofResponse           => pack_key = "TofResponse",
155        TofPacketType::RBCommand             => pack_key = "RBCommand",
156        TofPacketType::RBPing                => pack_key = "RBPing",
157        TofPacketType::PreampBiasConfig      => pack_key = "PreampBiasConfig",
158        TofPacketType::RunConfig             => pack_key = "RunConfig",
159        TofPacketType::LTBThresholdConfig    => pack_key = "LTBThresholdConfig",
160        TofPacketType::TofDetectorStatus     => pack_key = "TofDetectorStatus",
161        TofPacketType::ConfigBinary          => pack_key = "ConfigBinary",
162        TofPacketType::LiftofRBBinary        => pack_key = "LiftofRBBinary",
163        TofPacketType::LiftofBinaryService   => pack_key = "LiftofBinaryService",
164        TofPacketType::LiftofCCBinary        => pack_key = "LiftofCCBinary",
165        TofPacketType::RBCalibrationFlightV  => pack_key = "RBCalibrationFlightV",
166        TofPacketType::RBCalibrationFlightT  => pack_key = "RBCalibrationFlightT",
167        TofPacketType::BfswAckPacket         => pack_key = "BfswAckPacket",
168        TofPacketType::MultiPacket           => pack_key = "MultiPacket",
169      }
170      if pm.get(pack_key).is_some() {
171        *pm.get_mut(pack_key).unwrap() += 1;
172      } else {
173        pm.insert(pack_key, 0);
174      }
175    }
176    Err(err) => {
177      error!("Can't lock shared memory! {err}");
178    }
179  }
180}
181
182/// Receive packets from an incoming stream
183/// and distrubute them to their receivers
184/// while taking notes of everything
185///
186/// This is a Pablo Pubsub kind of persona
187/// (see a fantastic talk at RustConf 2023)
188pub fn packet_distributor(tp_from_sock : Receiver<TofPacket>,
189                          tp_sender_mt : Sender<TofPacket>,
190                          tp_sender_rb : Sender<TofPacket>,
191                          tp_sender_ev : Sender<TofPacket>,
192                          tp_sender_cp : Sender<TofPacket>,
193                          tp_sender_tr : Sender<TofPacket>,
194                          rbwf_sender  : Sender<TofPacket>,
195                          ts_send      : Sender<TofEvent>,
196                          th_send      : Sender<TofHit>,
197                          tp_sender_hb : Sender<TofPacket>,
198                          str_list     : Arc<Mutex<VecDeque<String>>>,
199                          pck_map      : Arc<Mutex<HashMap<&str, usize>>>,
200                          mut writer   : Option<TofPacketWriter>) {
201  let mut n_pack = 0usize;
202  // per default, we create master trigger packets from TofEventSummary, 
203  // except we have "real" mtb packets
204  let craft_mte_packets = true;
205
206  loop {
207    //match data_socket.recv_bytes(0) {
208    match tp_from_sock.recv() {
209      Err(err) => error!("Can't receive TofPacket! {err}"),
210      Ok(tp) => {
211        //println!("{:?}", pck_map);
212        packet_sorter(&tp.packet_type, &pck_map);
213        n_pack += 1;
214        //println!("Got TP {}", tp);
215        match str_list.lock() {
216          Err(err) => error!("Can't lock shared memory! {err}"),
217          Ok(mut _list)    => {
218            //let prefix  = String::from_utf8(payload[0..4].to_vec()).expect("Can't get prefix!");
219            //let message = format!("{}-{} {}", n_pack,prefix, tp.to_string());
220            let message = format!("{} : {}", n_pack, tp);
221            _list.push_back(message);
222          }
223        }
224        // if captured, write file
225        if writer.is_some() {
226          writer.as_mut().unwrap().add_tof_packet(&tp);
227        }
228        match tp.packet_type {
229          TofPacketType::TofResponse => { 
230            match tp_sender_tr.send(tp) {
231              Err(err) => error!("Can't send TP! {err}"),
232              Ok(_)    => (),
233            }
234          }
235          TofPacketType::MtbMoniData |
236          //TofPacketType::MasterTrigger => {
237          //  // apparently, we are getting MasterTriggerEvents, 
238          //  // sow we won't be needing to craft them from 
239          //  // TofEventSummary packets
240          //  if tp.packet_type == TofPacketType::MasterTrigger {
241          //    craft_mte_packets = false;
242          //  }
243          //  match tp_sender_mt.send(tp) {
244          //    Err(err) => error!("Can't send TP! {err}"),
245          //    Ok(_)    => (),
246          //  }
247          //},
248          TofPacketType::RBWaveform => {
249            match rbwf_sender.send(tp) {
250              Err(err) => error!("Can't send TP! {err}"),
251              Ok(_)    => (),
252            }
253          }
254          TofPacketType::TofEvent => {
255            //match TofEvent::from_tofpacket(&tp) {
256            match tp.unpack::<TofEvent>() {
257              Err(err) => {
258                error!("Unable to unpack TofEvent! {err}");
259              }
260              Ok(ts) => {
261                // FIXME - this is not needed anymore
262                if craft_mte_packets {
263                  //let mte    = MasterTriggerEvent::from(&ts);
264                  //let mte_tp = mte.pack();
265                  //error!("We are sending the following tp {}", mte_tp);
266                  match tp_sender_mt.send(tp.clone()) { 
267                  //match tp_sender_mt.send(mte_tp) {
268                    Err(err) => error!("Can't send MTE TP! {err}"),
269                    Ok(_)    => ()
270                  }
271                }
272                for h in &ts.hits {
273                  match th_send.send(*h) {
274                    Err(err) => error!("Can't send TP! {err}"),
275                    Ok(_)    => (),
276                  }
277                }
278                match ts_send.send(ts) {
279                  Err(err) => error!("Can't send TP! {err}"),
280                  Ok(_)    => (),
281                }
282                match tp_sender_ev.send(tp.clone()) {
283                  Err(err) => error!("Can't send TP! {err}"),
284                  Ok(_)    => (),
285                }
286              }
287            }
288          }
289          //TofPacketType::TofEvent => {
290          //  // since the tof event contains MTEs, we don't need
291          //  // to craft them
292          //  craft_mte_packets = false;
293          //  match tp_sender_ev.send(tp) {
294          //    Err(err) => error!("Can't send TP! {err}"),
295          //    Ok(_)    => (),
296          //  }
297          //  // Disasemble the packets
298          //  //match TofEvent::from_bytestream(tp.payload, &mut 0) {
299          //  //  Err(err) => {
300          //  //    error!("Can't decode TofEvent");
301          //  //  },
302          //  //  Ok(ev) => {
303          //  //    //for rbev in ev.rb_events {
304          //  //    //  let 
305          //  //    //  match tp_sender_rb.send
306          //  //    //}
307          //  //  }
308          //  //}
309          //}
310          TofPacketType::RBEvent |
311          TofPacketType::RBEventMemoryView | 
312          TofPacketType::LTBMoniData |
313          TofPacketType::PAMoniData  |
314          TofPacketType::PBMoniData  |
315          TofPacketType::RBMoniData => {
316            match tp_sender_rb.send(tp) {
317              Err(err) => error!("Can't send TP! {err}"),
318              Ok(_)    => (),
319            }
320          }
321          TofPacketType::CPUMoniData => {
322            match tp_sender_cp.send(tp) {
323              Err(err) => error!("Can't send TP! {err}"),
324              Ok(_)    => (),
325            }
326          }
327          TofPacketType::DataSinkHB      |
328          TofPacketType::EventBuilderHB  | 
329          TofPacketType::MasterTriggerHB => {
330            match tp_sender_hb.send(tp) {
331              Err(err) => error!("Can't send TP! {err}"),
332              Ok(_)    => {
333              },
334            }
335          }
336          _ => () 
337        }
338      }
339    } 
340  }
341}
342
343///// ZMQ socket wrapper for the zmq socket which is 
344///// supposed to receive data from the TOF system.
345//pub fn socket_wrap_tofstream(address   : &str,
346//                             tp_sender : Sender<TofPacket>) {
347//  let ctx = zmq::Context::new();
348//  // FIXME - don't hardcode this IP
349//  let socket = ctx.socket(zmq::SUB).expect("Unable to create 0MQ SUB socket!");
350//  socket.connect(address).expect("Unable to connect to data (PUB) socket {adress}");
351//  socket.set_subscribe(b"").expect("Can't subscribe to any message on 0MQ socket!");
352//  //let mut n_pack = 0usize;
353//  info!("0MQ SUB socket connected to address {address}");
354//  // per default, we create master trigger packets from TofEventSummary, 
355//  // except we have "real" mtb packets
356//  //let mut craft_mte_packets = true;
357//  loop {
358//    match socket.recv_bytes(0) {
359//      Err(err) => error!("Can't receive TofPacket! {err}"),
360//      Ok(payload)    => {
361//        match TofPacket::from_bytestream(&payload, &mut 0) {
362//          Ok(tp) => {
363//            match tp_sender.send(tp) {
364//              Ok(_) => (),
365//              Err(err) => error!("Can't send TofPacket over channel! {err}")
366//            }
367//          }
368//          Err(err) => {
369//            debug!("Can't decode payload! {err}");
370//            // that might have an RB prefix, forward 
371//            // it 
372//            match TofPacket::from_bytestream(&payload, &mut 4) {
373//              Err(err) => {
374//                error!("Don't understand bytestream! {err}"); 
375//              },
376//              Ok(tp) => {
377//                match tp_sender.send(tp) {
378//                  Ok(_) => (),
379//                  Err(err) => error!("Can't send TofPacket over channel! {err}")
380//                }
381//              }
382//            }
383//          }  
384//        }
385//      }
386//    }
387//  }
388//}
389//
390////use telemetry_dataclasses::packets::{
391////  TelemetryPacketHeader,
392////  TelemetryPacket,
393////};
394//
395///// Get the GAPS merged event telemetry stream and 
396///// broadcast it to the relevant tab
397/////
398///// # Arguments
399/////
400///// * address     : Address to susbscribe to for telemetry 
401/////                 stream (must be zmq.PUB) on the Sender
402/////                 side
403///// * cachesize   : Getting the packets from the funneled stream leads
404/////                 to duplicates. To eliminate these, we store the 
405/////                 packet counter variable in a Dequee of a given 
406/////                 size
407///// * tele_sender : Channel to forward the received telemetry
408/////                 packets
409//pub fn socket_wrap_telemetry(address     : &str,
410//                             cachesize   : usize,
411//                             tele_sender : Sender<TelemetryPacket>) {
412//  let ctx = zmq::Context::new();
413//  // FIXME - don't hardcode this IP
414//  // typically how it is done is that this program runs either on a gse
415//  // or there is a local forwarding of the port thrugh ssh
416//  //let address : &str = "tcp://127.0.0.1:55555";
417//  let socket = ctx.socket(zmq::SUB).expect("Unable to create 0MQ SUB socket!");
418//  match socket.connect(&address) {
419//    Err(err) => {
420//      error!("Unable to connect to data (PUB) socket {address}! {err}");
421//      panic!("Can not connect to zmq PUB socket!");
422//    }
423//    Ok(_) => ()
424//  }
425//  let mut cache = VecDeque::<u16>::with_capacity(cachesize);
426//  socket.set_subscribe(b"") .expect("Can't subscribe to any message on 0MQ socket! {err}");
427//  loop {
428//    match socket.recv_bytes(0) {
429//      Err(err)    => error!("Can't receive TofPacket! {err}"),
430//      Ok(mut payload) => {
431//        match TelemetryPacketHeader::from_bytestream(&payload, &mut 0) {
432//          Err(err) => {
433//            error!("Can not decode telemtry header! {err}");
434//            //for k in pos - 5 .. pos + 5 {
435//            //  println!("{}",stream[k]);
436//            //}
437//          }
438//          Ok(header) => {
439//            let mut packet = TelemetryPacket::new();
440//            if payload.len() > TelemetryPacketHeader::SIZE {
441//              payload.drain(0..TelemetryPacketHeader::SIZE);
442//            }
443//            if cache.contains(&header.counter) {
444//              // drop this packet
445//              continue;
446//            } else {
447//              cache.push_back(header.counter); 
448//            }
449//            if cache.len() == cachesize {
450//              cache.pop_front();
451//            }
452//
453//            packet.header  = header;
454//            packet.payload = payload;
455//            match tele_sender.send(packet) {
456//              Err(err) => error!("Can not send telemetry packet to downstream! {err}"),
457//              Ok(_)    => ()
458//            }
459//          }
460//        }
461//      }
462//    }
463//  }
464//}
465