liftof_tui/tabs/
tab_commands.rs1use ratatui::prelude::*;
6use ratatui::widgets::{
7 Block,
8 BorderType,
9 Borders,
10 List,
13 ListItem,
14 ListState,
15};
16
17use std::collections::VecDeque;
18use crossbeam_channel::{
19 Receiver
22};
23
24use gondola_core::prelude::*;
25
26use crate::colors::ColorTheme;
43
44pub struct CommandTab<'a> {
45 pub resp_rc : Receiver<TofPacket>,
46 pub theme : ColorTheme,
47 pub cmd_sender : zmq::Socket,
48 pub cmdl_state : ListState,
50 pub cmdl_items : Vec::<ListItem<'a>>,
51 pub cmdl_active : bool,
52 pub cmdl_selector : usize,
53 pub allow_commands : bool,
54 pub active_cmd : TofCommand,
55 pub commands : Vec<TofCommand>,
56 pub queue_size : usize,
57 pub tr_queue : VecDeque<TofResponse>,
58}
59
60
61impl CommandTab<'_> {
62
63 pub fn new<'a>(resp_rc : Receiver<TofPacket>,
64 cmd_pub_addr : String,
65 theme : ColorTheme,
66 allow_commands : bool) -> CommandTab<'a> {
67 let mut ping_cmd = TofCommand::new();
68 ping_cmd.command_code = TofCommandCode::Ping;
69 let mut start_cmd = TofCommand::new();
70 start_cmd.command_code = TofCommandCode::DataRunStart;
71 let mut stop_cmd = TofCommand::new();
72 stop_cmd.command_code = TofCommandCode::DataRunStop;
73 let mut cali_cmd = TofCommand::new();
74 cali_cmd.command_code = TofCommandCode::RBCalibration;
75
76 let mut send_te = TofCommand::new();
77 send_te.command_code = TofCommandCode::SendTofEvents;
78 let mut no_send_te = TofCommand::new();
79 no_send_te.command_code = TofCommandCode::NoSendTofEvents;
80
81 let mut send_rw = TofCommand::new();
82 send_rw.command_code = TofCommandCode::SendRBWaveforms;
83 let mut no_send_rw = TofCommand::new();
84 no_send_rw.command_code = TofCommandCode::NoSendRBWaveforms;
85
86 let mut kill_cmd = TofCommand::new();
87 kill_cmd.command_code = TofCommandCode::Kill;
88
89
90 let commands = vec![ping_cmd,
91 start_cmd,
92 stop_cmd,
93 cali_cmd,
94 send_te,
95 no_send_te,
96 send_rw,
97 no_send_rw,
98 kill_cmd];
99
100 let mut cmd_select_items = Vec::<ListItem>::new();
101 for k in &commands {
102 let this_item = format!("{:?}", k.command_code);
103 cmd_select_items.push(ListItem::new(Line::from(this_item)));
104 }
105 let ctx = zmq::Context::new();
106 let cmd_sender = ctx.socket(zmq::PUB).expect("Can not create 0MQ PUB socket!");
107 if allow_commands {
108 cmd_sender.bind(&cmd_pub_addr).expect("Unable to bind to (PUB) socket!");
109 }
110 CommandTab {
113 theme ,
114 resp_rc ,
115 cmd_sender ,
116 cmdl_state : ListState::default(),
117 cmdl_items : cmd_select_items,
118 cmdl_active : false,
119 cmdl_selector : 0,
120 allow_commands : allow_commands,
121 active_cmd : TofCommand::new(),
122 commands : commands,
123 queue_size : 1000,
124 tr_queue : VecDeque::<TofResponse>::new(),
125 }
126 }
127
128 pub fn next_cmd(&mut self) {
129 let i = match self.cmdl_state.selected() {
130 Some(i) => {
131 if i >= self.cmdl_items.len() - 1 {
132 self.cmdl_items.len() - 1
133 } else {
134 i + 1
135 }
136 }
137 None => 0,
138 };
139 self.cmdl_state.select(Some(i));
140 self.active_cmd = self.commands.get(i).unwrap().clone();
141 }
143
144 pub fn prev_cmd(&mut self) {
145 let i = match self.cmdl_state.selected() {
146 Some(i) => {
147 if i == 0 {
148 0
149 } else {
150 i - 1
151 }
152 }
153 None => 0,
154 };
155 self.cmdl_state.select(Some(i));
156 self.active_cmd = self.commands.get(i).unwrap().clone();
157 }
158
159 pub fn send_command(&self) {
161 if !self.allow_commands {
162 error!("To send commands, run program with --send-commands!");
163 return;
164 }
165 let payload = self.active_cmd.pack().to_bytestream();
166 match self.cmd_sender.send(&payload, 0) {
167 Err(err) => {
168 error!("Unable to send command! {err}");
169 },
170 Ok(_) => {
171 info!("TOF cmd {} sent!", self.active_cmd);
172 }
173 }
174 }
175
176 pub fn receive_packet(&mut self) -> Result<(), SerializationError> {
178 match self.resp_rc.try_recv() {
179 Err(_err) => {
180 debug!("Unable to receive ACK TofPacket!");
181 }
182 Ok(pack) => {
183 match pack.packet_type {
185 TofPacketType::TofResponse => {
186 let tr : TofResponse = pack.unpack()?;
187 self.tr_queue.push_back(tr);
188 if self.tr_queue.len() > self.queue_size {
189 self.tr_queue.pop_front();
190 }
191 }
192 _ => () }
194 }
195 }
196 Ok(())
197 }
198
199 pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
200
201 let main_lo = Layout::default()
202 .direction(Direction::Horizontal)
203 .constraints(
204 [Constraint::Percentage(20), Constraint::Percentage(80)].as_ref(),
205 )
206 .split(*main_window);
207 let par_title_string = String::from("Select Command");
208 let (first, rest) = par_title_string.split_at(1);
209
210 let par_title = Line::from(vec![
211 Span::styled(
212 first,
213 Style::default()
214 .fg(self.theme.hc)
215 .add_modifier(Modifier::UNDERLINED),
216 ),
217 Span::styled(rest, self.theme.style()),
218 ]);
219
220 let cmds = Block::default()
221 .borders(Borders::ALL)
222 .style(self.theme.style())
223 .title(par_title)
224 .border_type(BorderType::Plain);
225
226 let cmd_select_list = List::new(self.cmdl_items.clone()).block(cmds)
227 .highlight_style(self.theme.highlight().add_modifier(Modifier::BOLD))
228 .highlight_symbol(">>")
229 .repeat_highlight_symbol(true);
230
231 match self.cmdl_state.selected() {
232 None => {
233 self.cmdl_selector = 0;
234 },
235 Some(cmd_id) => {
236 let selector = cmd_id;
238 if self.cmdl_selector != selector {
239 self.cmdl_selector = selector;
242 } else {
243 }
245 },
246 }
247 if self.allow_commands {
248 frame.render_stateful_widget(cmd_select_list, main_lo[0], &mut self.cmdl_state );
249 }
250 }
251}