Jpp  18.4.0
the software that should make you happy
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gui.cpp
Go to the documentation of this file.
1 #include "gui.hpp"
2 #include "structs.hpp"
3 #include "version.hpp"
4 
5 #include <boost/bind.hpp>
6 #include <sys/ioctl.h>
7 #include <boost/ref.hpp>
8 #include <sstream>
9 #include <fstream>
10 
11 /**
12  * \author cpellegrino
13  */
14 
15 const static int default_hit_counter_threshold = 850;
16 
17 std::string mon_channel::mac_address() const
18 {
19  /*
20  * The MAC address of a WR node starts with 08:00:30.
21  * The DOMID is defined by the MAC address removing the initial 08:00.
22  */
23 
24  std::ostringstream oss("0800", std::ostringstream::ate);
25  oss << std::hex << domid();
26  if (oss.tellp() != 12) {
27  return "undefined";
28  }
29 
30  std::ostringstream stream;
31 
32  std::string const no = oss.str();
33  std::size_t const s = no.size();
34  for (std::size_t i = 0; i < s; i += 2) {
35  stream << char(toupper(no[i]))
36  << char(toupper(no[i + 1]))
37  << (i != s - 2 ? ":" : "");
38  }
39  return stream.str();
40 }
41 
42 inline
43 bool ischar(int key)
44 {
45  return
46  key >= std::numeric_limits<char>::min()
47  && key <= std::numeric_limits<char>::max();
48 }
49 
51  boost::asio::deadline_timer& timer,
52  gui::Screen& screen,
53  boost::system::error_code const& error)
54 {
55  if (!error) {
56  screen.commit();
57 
58  timer.expires_from_now(boost::posix_time::seconds(1));
59  timer.async_wait(
60  boost::bind(
62  boost::ref(timer),
63  boost::ref(screen),
64  boost::asio::placeholders::error));
65  }
66 }
67 
68 void async_cin(
69  boost::asio::posix::stream_descriptor& keyb,
70  char& key,
71  gui::Screen& screen,
72  const boost::system::error_code& error,
73  std::size_t bytes_transferred)
74 {
75  if (!error) {
76  int k = key;
77 
78  if (key == 27) {
79  boost::asio::posix::stream_descriptor::bytes_readable command(true);
80  keyb.io_control(command);
81 
82  std::size_t nbytes = command.get();
83 
84  while (nbytes--) {
85  boost::system::error_code ec;
86  keyb.read_some(boost::asio::buffer(&key, sizeof(key)), ec);
87  k <<= 8;
88  k += key;
89  }
90  }
91 
92  screen.elaborate(k);
93 
94  keyb.async_read_some(
95  boost::asio::buffer(&key, sizeof(key)),
96  boost::bind(
97  async_cin,
98  boost::ref(keyb),
99  boost::ref(key),
100  boost::ref(screen),
101  boost::asio::placeholders::error,
102  boost::asio::placeholders::bytes_transferred));
103  }
104 }
105 
107  boost::asio::signal_set& window_resize,
108  gui::Screen& screen,
109  boost::system::error_code const& error,
110  int signum)
111 {
112  if (!error) {
113  std::pair<int, int> const win_size = window_size();
114 
115  screen.resize(win_size.first, win_size.second);
116 
117  window_resize.async_wait(
118  boost::bind(
120  boost::ref(window_resize),
121  boost::ref(screen),
122  boost::asio::placeholders::error,
123  boost::asio::placeholders::signal_number));
124  }
125 }
126 
128 {
129  winsize sz;
130 
131  ioctl(0, TIOCGWINSZ, &sz);
132 
133  return std::make_pair(sz.ws_row, sz.ws_col);
134 }
135 
136 namespace gui {
137 
138 std::string const Screen::search_prompt = "Search: ";
139 std::string const Screen::regex_prompt = "RegEx: ";
140 
141 void LineEdit::move(LineEdit::movement dir)
142 {
143  switch (dir) {
144  case LEFT:
145  m_current_pos -= m_current_pos == 0 ? 0 : 1;
146  break;
147  case RIGHT:
148  m_current_pos += m_current_pos == m_current_line.size() ? 0 : 1;
149  break;
150  case BEGIN:
151  m_current_pos = 0;
152  break;
153  case END:
154  m_current_pos = m_current_line.size();
155  break;
156  case HBACK:
157  if (not m_history.empty()) {
158  if (m_history_pos == m_history.size()) {
159  m_editing_line.swap(m_current_line);
160  }
161 
162  if (m_history_pos != 0) {
163  --m_history_pos;
164 
165  std::list<std::string>::iterator it = m_history.begin();
166  std::advance(it, m_history_pos);
167 
168  m_current_line = *it;
169  m_current_pos = m_current_line.size();
170  }
171  }
172  break;
173  case HFWD:
174  if (not m_history.empty()) {
175  if (m_history_pos == m_history.size() - 1) {
176  m_editing_line.swap(m_current_line);
177  ++m_history_pos;
178  m_current_pos = m_current_line.size();
179  } else if (m_history_pos < m_history.size()) {
180  ++m_history_pos;
181 
182  std::list<std::string>::iterator it = m_history.begin();
183  std::advance(it, m_history_pos);
184 
185  m_current_line = *it;
186  m_current_pos = m_current_line.size();
187  }
188  }
189  break;
190  }
191 }
192 
193 void LineEdit::load_history(std::string const& path)
194 {
195  std::ifstream ifs(path.c_str());
196 
197  while (ifs && ifs.peek() != EOF) {
198  std::string line;
199  std::getline(ifs, line);
200 
201  m_history.push_back(line);
202  }
203 }
204 
205 void LineEdit::store_history(std::string const& path) const
206 {
207  std::ofstream ofs(path.c_str());
209  for (
210  citer it = m_history.begin(), et = m_history.end()
211  ; it != et
212  ; ++it
213  ) {
214  ofs << *it << '\n';
215  }
216 }
217 
218 void Screen::elaborate(int key)
219 {
220  if (status != kSEARCH && status != kREGEX) {
221  clear_status_bar();
222 
223  if (key == 'q') {
224  m_service.stop();
225  return;
226  }
227  }
228 
229  switch (status) {
230  case kNORMAL:
231  if (key == 'h') {
232  show_help();
233  status = kHELP;
234  } else if (key == 'c') {
235  m_list.clear();
236  m_smatched.clear();
237  m_selected = 0;
238  commit();
239  } else if (key == 't') {
240  sort = kLAST_VIEW;
241  commit();
242  } else if (key == 'd') {
243  sort = kDOMID;
244  commit();
245  } else if (key == 'r') {
246  sort = kRATE;
247  commit();
248  } else if (key == 'n') {
249  sort = kRUNNO;
250  commit();
251  } else if (key == 'l') {
252  sort = kNAME;
253  commit();
254  } else if (key == 'i') {
255  m_sort_reverse = !m_sort_reverse;
256  commit();
257  } else if (key == 'g') {
258  if (m_list.size()) {
259  m_selected = 0;
260 
261  move_limits();
262 
263  move_selection();
264  }
265  } else if (key == 'G') {
266  if (m_list.size()) {
267  m_selected = m_list.size() - 1;
268 
269  move_limits();
270 
271  move_selection();
272  }
273  } else if (key == '/') {
274  status = kSEARCH;
275  m_search_editor.reset();
276  update_bar(search_prompt, m_search_editor);
277  } else if (key == '%') {
278  status = kREGEX;
279  m_regex_editor.reset();
280  update_bar(regex_prompt, m_regex_editor);
281  } else if (key == 'm') {
282  m_matching_first = ! m_matching_first;
283 
284  if (m_matching_first) {
285  write_to_status_bar("Grouping matching CLBs on top");
286  } else {
287  write_to_status_bar("Grouping disabled");
288  }
289  } else if (key == 'w') {
290  go_match = NONE;
291  m_smatched.clear();
292  } else if (key == kKEY_ENTER) {
293  if (m_list.size()) {
294  status = kSINGLE;
295  show_filtered();
296  } else {
297  status_nodoms();
298  }
299  } else if (key == kKEY_DOWN) {
300  if (m_list.size()) {
301  m_selected =
302  m_selected + 1 == static_cast<int>(m_list.size())
303  ? 0
304  : m_selected + 1;
305 
306  move_limits();
307 
308  move_selection();
309  }
310  } else if (key == kKEY_UP) {
311  if (m_list.size()) {
312  m_selected =
313  m_selected - 1 < 0
314  ? m_list.size() - 1
315  : m_selected - 1;
316 
317  move_limits();
318 
319  move_selection();
320  }
321  } else if (key == kKEY_LEFT) {
322  if (m_offset != 0) {
323  m_offset -= 5;
324  commit();
325  }
326  } else if (key == kKEY_RIGHT) {
327  if (m_offset + COLS + 1 < max_line_size) {
328  m_offset += 5;
329  commit();
330  }
331  } else {
332  status_unrecognised(key);
333  }
334  break;
335  case kHELP:
336  if (key == kKEY_ESC) {
337  status = kNORMAL;
338  commit();
339  } else {
340  status_unrecognised(key);
341  }
342  break;
343  case kSINGLE:
344  if (key == kKEY_ESC) {
345  status = kNORMAL;
346  commit();
347  } else if (key == kKEY_DOWN) {
348  if (m_list.size()) {
349  m_selected =
350  m_selected + 1 == static_cast<int>(m_list.size())
351  ? 0
352  : m_selected + 1;
353 
354  move_limits();
355 
356  move_selection();
357  }
358  } else if (key == kKEY_UP) {
359  if (m_list.size()) {
360  m_selected =
361  m_selected - 1 < 0
362  ? m_list.size() - 1
363  : m_selected - 1;
364 
365  move_limits();
366 
367  move_selection();
368  }
369  } else {
370  status_unrecognised(key);
371  }
372  break;
373  case kSEARCH:
374  if (key == kKEY_ESC) {
375  clear_status_bar();
376 
377  if (!m_search_editor.current().empty()) {
378  m_search_editor.add_history();
379  }
380 
381  status = kNORMAL;
382  go_match = NONE;
383  m_smatched.clear();
384  return;
385  } else if (key == kKEY_ENTER) {
386  go_match = SEARCH;
387  m_search_editor.add_history();
388  clear_status_bar();
389  status = kNORMAL;
390  return;
391  } else if (key == kKEY_UP) {
392  m_search_editor.move(LineEdit::HBACK);
393  } else if (key == kKEY_DOWN) {
394  m_search_editor.move(LineEdit::HFWD);
395  } else if (key == kKEY_RIGHT) {
396  m_search_editor.move(LineEdit::RIGHT);
397  } else if (key == kKEY_LEFT) {
398  m_search_editor.move(LineEdit::LEFT);
399  } else if (key == kKEY_BACKS) {
400  m_search_editor.remove_bwd();
401  } else if (key == kKEY_DEL) {
402  m_search_editor.remove_fwd();
403  } else if (key == kKEY_HOME || key == kKEY_CTRLA) {
404  m_search_editor.move(LineEdit::BEGIN);
405  } else if (key == kKEY_END || key == kKEY_CTRLE) {
406  m_search_editor.move(LineEdit::END);
407  } else if (key == kKEY_CTRLL) {
408  m_search_editor.reset();
409  } else if (ischar(key) && isprint(key)) {
410  m_search_editor.append(key);
411  } else {
412  return;
413  }
414  update_bar(search_prompt, m_search_editor);
415  go_match = SEARCH;
416  commit();
417  break;
418  case kREGEX:
419  if (key == kKEY_ESC) {
420  clear_status_bar();
421  status = kNORMAL;
422  return;
423  } else if (key == kKEY_ENTER) {
424  if (!m_regex_editor.current().empty()) {
425  m_regex_editor.add_history();
426  }
427 
428  std::string const current_line = m_regex_editor.current();
429  m_regex_editor.reset();
430  clear_status_bar();
431  status = kNORMAL;
432 
433  try {
434  m_regex.assign(current_line, boost::regex_constants::icase);
435  go_match = REGEX;
436  commit();
437  } catch (...) {
438  write_to_status_bar("Invalid regex");
439  go_match = NONE;
440  m_smatched.clear();
441  }
442  return;
443  } else if (key == kKEY_UP) {
444  m_regex_editor.move(LineEdit::HBACK);
445  } else if (key == kKEY_DOWN) {
446  m_regex_editor.move(LineEdit::HFWD);
447  } else if (key == kKEY_RIGHT) {
448  m_regex_editor.move(LineEdit::RIGHT);
449  } else if (key == kKEY_LEFT) {
450  m_regex_editor.move(LineEdit::LEFT);
451  } else if (key == kKEY_BACKS) {
452  m_regex_editor.remove_bwd();
453  } else if (key == kKEY_DEL) {
454  m_regex_editor.remove_fwd();
455  } else if (key == kKEY_HOME || key == kKEY_CTRLA) {
456  m_regex_editor.move(LineEdit::BEGIN);
457  } else if (key == kKEY_END || key == kKEY_CTRLE) {
458  m_regex_editor.move(LineEdit::END);
459  } else if (key == kKEY_CTRLL) {
460  m_regex_editor.reset();
461  } else if (ischar(key) && isprint(key)) {
462  m_regex_editor.append(key);
463  } else {
464  return;
465  }
466  update_bar(regex_prompt, m_regex_editor);
467  break;
468  default:
469  assert(! "Internal screen error");
470  }
471 }
472 
473 void Screen::update_bar(std::string const& prompt, LineEdit const& le)
474 {
475  werase(m_twin);
476  wprintw(m_twin, "%s", prompt.c_str());
477  wprintw(m_twin, "%s", le.current().c_str());
478  wmove(m_twin, 0, le.cursor() + prompt.size());
479  wnoutrefresh(m_twin);
480  doupdate();
481 }
482 
483 void Screen::show_help() const
484 {
485  int const col1 = 2;
486  int const col2 = 33;
487 
488  int const cols = 70;
489  int const lines = 16;
490  int const x_pos = (COLS - cols) / 2;
491  int const y_pos = (LINES - lines) / 2;
492  WINDOW* help_win = newwin(lines, cols, y_pos, x_pos);
493  box(help_win, 0, 0);
494  wmove(help_win, 0, 6);
495  wprintw(help_win, " Help ");
496  wmove(help_win, 1, col1);
497  wprintw(help_win, "Press the key to activate the corresponding behaviour.");
498  wmove(help_win, 3, col1);
499  wprintw(help_win, "Sort:");
500  wmove(help_win, 4, col1);
501  wprintw(help_win, "- t: sort by last view time");
502  wmove(help_win, 5, col1);
503  wprintw(help_win, "- d: sort by DOM ID");
504  wmove(help_win, 6, col1);
505  wprintw(help_win, "- r: sort by avg hit rate");
506  wmove(help_win, 7, col1);
507  wprintw(help_win, "- n: sort by run number");
508  wmove(help_win, 8, col1);
509  wprintw(help_win, "- l: sort by label (name)");
510  wmove(help_win, 9, col1);
511  wprintw(help_win, "- i: invert sorting");
512  wmove(help_win, 3, col2);
513  wprintw(help_win, "Screen:");
514  wmove(help_win, 4, col2);
515  wprintw(help_win, "- c: clear the screen");
516  wmove(help_win, 5, col2);
517  wprintw(help_win, "- Arrow keys: move selection/view");
518  wmove(help_win, 6, col2);
519  wprintw(help_win, "- g: move selection to top");
520  wmove(help_win, 7, col2);
521  wprintw(help_win, "- G: move selection to bottom");
522  wmove(help_win, 8, col2);
523  wprintw(help_win, "- /: open search prompt");
524  wmove(help_win, 9, col2);
525  wprintw(help_win, "- %%: open regex prompt");
526  wmove(help_win, 10, col2);
527  wprintw(help_win, "- w: wipe the search/regex status");
528  wmove(help_win, 11, col2);
529  wprintw(help_win, "- m: toggle grouping matches on top");
530  wmove(help_win, 13, col1);
531  wprintw(help_win, "Press ESC to dismiss this win");
532  wmove(help_win, 14, col1);
533  wprintw(help_win, "Version %s", clbsk::version::v().c_str());
534 
535  wnoutrefresh(help_win);
536  delwin(help_win);
537  reset_cursor();
538 }
539 
540 bool is_problematic(mon_channel const& channel)
541 {
542  return
543  ! channel.syncd()
544  || channel.mean() > default_hit_counter_threshold
545  || boost::chrono::duration_cast<boost::chrono::seconds>(channel.last_view())
546  > boost::chrono::seconds(2);
547 }
548 
549 void Screen::write_head() const
550 {
551  bool const problematic = std::find_if(
552  m_list.begin()
553  , m_list.end()
555  ) != m_list.end();
556 
557  werase(m_hwin);
558  wmove(m_hwin, 0, 0);
559 
560  if (m_smatched.empty()) {
561  wprintw(
562  m_hwin
563  , "CLBSK - %s - # CLBs:%c %ld - 'q' to quit, 'h' for help"
564  , m_heading.c_str()
565  , problematic ? '!' : ' '
566  , m_list.size()
567  );
568  } else {
569  wprintw(
570  m_hwin
571  , "CLBSK - %s - # CLBs:%c %ld (%ld) - 'q' to quit, 'h' for help"
572  , m_heading.c_str()
573  , problematic ? '!' : ' '
574  , m_list.size()
575  , m_smatched.size()
576  );
577  }
578 
579  wnoutrefresh(m_hwin);
580  reset_cursor();
581 }
582 
583 void Screen::write_page()
584 {
585  werase(m_cwin);
586  box(m_cwin, 0, 0);
587  if (m_upper != 0) {
588  mvwaddstr(m_cwin, 0, 3, "^");
589  }
590 
591  if (m_lower < static_cast<int>(m_list.size())) {
592  mvwaddstr(m_cwin, LINES - 3, 3, "v");
593  }
594 
595  wmove(m_cwin, 1, 2);
596  print_table_head(m_cwin, m_offset);
597 
598  int count = 1;
599  typedef ChList::const_iterator citerator;
600 
601  citerator it = m_list.begin(), et = m_list.end();
602  std::advance(it, m_upper);
603 
604  for (int vcount = m_upper; it != et && vcount < m_lower; ++vcount, ++it) {
605  wmove(m_cwin, ++count, 2);
606  print_chan(
607  m_cwin
608  , it
609  , m_linebuffer
610  , COLS + m_offset - 3
611  , m_offset
612  , std::find(m_smatched.begin(), m_smatched.end(), it) != m_smatched.end()
613  );
614 
615  if (count - 2 == m_selected - m_upper) {
616  mvwaddstr(m_cwin, count, 1, ">");
617  }
618  }
619  wnoutrefresh(m_cwin);
620  reset_cursor();
621 }
622 
623 void Screen::move_limits()
624 {
625  if (m_upper > m_selected) {
626  m_upper = m_selected;
627  m_lower = m_upper + LINES - 5;
628  }
629  if (m_lower <= m_selected) {
630  m_lower = m_selected + 1;
631  m_upper = m_lower - LINES + 5;
632  }
633 }
634 
635 void Screen::show_filtered(CLBCommonHeader const* header)
636 {
637  ChList::const_iterator it = m_list.begin();
638  std::advance(it, m_selected);
639 
640  if (header->domIdentifier() == it->domid()) {
641  werase(m_cwin);
642  box(m_cwin, 0, 0);
643  wmove(m_cwin, 1, 2);
644  wprintw(m_cwin, "Press ESC to return back.");
645 
646  wmove(m_cwin, 2, 2);
647  print_table_head(m_cwin, 0);
648  wmove(m_cwin, 3, 2);
649  print_chan(m_cwin, it, m_linebuffer, COLS - 3, 0, false);
650 
651  uint32_t const*const data = static_cast<uint32_t const*>(
652  static_cast<void const*>(header + 1));
653 
654  wmove(m_cwin, 5, 2);
655 
656  bool const valid = validTimeStamp(*header);
657 
659  m_cwin,
660  header->timeStamp(),
661  m_linebuffer,
662  COLS - 3,
663  0,
664  valid);
665 
666  wmove(m_cwin, 7, 2);
667 
668  for (int i = 0; i < 31; ++i) {
669  wprintw(m_cwin, "CH%02d: %5d", i, ntohl(data[i]));
670 
671  int y = 0, x = 0;
672  getyx(m_cwin, y, x);
673 
674  if (x + 15 > COLS) {
675  wmove(m_cwin, y + 1, 2);
676  } else {
677  wmove(m_cwin, y, x + 2);
678  }
679  }
680 
681  int y = 0, x = 0;
682  getyx(m_cwin, y, x);
683 
684  char const*const raw_data = static_cast<char const*>(
685  static_cast<void const*>(header));
686 
687  SCData const*const scdata = static_cast<SCData const*>(
688  static_cast<void const*>(
689  raw_data + sizeof(*header) + 31 * sizeof(uint32_t)));
690 
691  wmove(m_cwin, y + 2, 2);
692  wprintw(m_cwin, "Validity: 0x%x", ntohl(scdata->valid));
693 
694  wmove(m_cwin, y + 3, 2);
695  wprintw(
696  m_cwin,
697  "Yaw: %4.4f Pitch: %4.4f Roll: %4.4f deg",
698  ntohl_f(scdata->ahrs.yaw),
699  ntohl_f(scdata->ahrs.pitch),
700  ntohl_f(scdata->ahrs.roll));
701 
702  wmove(m_cwin, y + 4, 2);
703  wprintw(
704  m_cwin,
705  "Acceleration: %4.4f, %4.4f, %4.4f g",
706  ntohl_f(scdata->ahrs.ax),
707  ntohl_f(scdata->ahrs.ay),
708  ntohl_f(scdata->ahrs.az));
709 
710  wmove(m_cwin, y + 5, 2);
711  wprintw(
712  m_cwin,
713  "Gyroscope: %4.4f, %4.4f, %4.4f deg/sec",
714  ntohl_f(scdata->ahrs.gx),
715  ntohl_f(scdata->ahrs.gy),
716  ntohl_f(scdata->ahrs.gz));
717 
718  wmove(m_cwin, y + 6, 2);
719  wprintw(m_cwin,
720  "Compass: %4.4f, %4.4f, %4.4f gauss",
721  ntohl_f(scdata->ahrs.hx),
722  ntohl_f(scdata->ahrs.hy),
723  ntohl_f(scdata->ahrs.hz));
724 
725  wmove(m_cwin, y + 7, 2);
726  wprintw(m_cwin, "Temperature: %.2f Celsius", ntohs(scdata->temp) / 100.);
727 
728  wmove(m_cwin, y + 8, 2);
729  wprintw(m_cwin, "Humidity: %.2f RH", ntohs(scdata->humidity) / 100.);
730 
731  wnoutrefresh(m_cwin);
732  reset_cursor();
733  }
734 }
735 
736 bool matches(mon_channel const& ch, std::string const& pattern)
737 {
738  return
739  pattern.size() != 0
740  && (
741  ch.name().find(pattern) != std::string::npos
742  || ch.mac_address().find(pattern) != std::string::npos
743  || boost::lexical_cast<std::string>(ch.domid()).find(pattern) != std::string::npos
744  );
745 }
746 
747 void Screen::search()
748 {
749  m_smatched.clear();
750 
751  for (
752  ChList::const_iterator it = m_list.begin(), et = m_list.end()
753  ; it != et
754  ; ++it
755  ) {
756  if (matches(*it, m_search_editor.current())) {
757  m_smatched.push_back(it);
758  }
759  }
760 }
761 
762 bool matches(mon_channel const& ch, boost::regex const& regex)
763 {
764  return
765  boost::regex_match(ch.name(), regex)
766  || boost::regex_match(ch.mac_address(), regex)
767  || boost::regex_match(boost::lexical_cast<std::string>(ch.domid()), regex);
768 }
769 
770 void Screen::filter()
771 {
772  m_smatched.clear();
773 
774  for (
775  ChList::const_iterator it = m_list.begin(), et = m_list.end()
776  ; it != et
777  ; ++it
778  ) {
779  if (matches(*it, m_regex)) {
780  m_smatched.push_back(it);
781  }
782  }
783 }
784 
785 bool Screen::is_filter() const
786 {
787  return status == kSINGLE;
788 }
789 
790 bool Screen::is_user_input() const
791 {
792  return status >= kSEARCH;
793 }
794 
796 {
797  bool m_reverse;
798 
799  public:
800 
801  explicit
802  domid_comparator(bool reverse)
803  :
804  m_reverse(reverse)
805  {}
806 
807  bool operator ()(mon_channel const& first, mon_channel const& second)
808  {
809  return m_reverse
810  ? first.domid() < second.domid()
811  : first.domid() > second.domid();
812  }
813 };
814 
816 {
817  bool m_reverse;
818 
819  public:
820 
821  explicit
822  last_view_comparator(bool reverse)
823  :
824  m_reverse(reverse)
825  {}
826 
827  bool operator ()(mon_channel const& first, mon_channel const& second)
828  {
829  using namespace boost::chrono;
830  return m_reverse
831  ? duration_cast<seconds>(first.last_view()) < duration_cast<seconds>(second.last_view())
832  : duration_cast<seconds>(first.last_view()) > duration_cast<seconds>(second.last_view());
833  }
834 };
835 
837 {
838  bool m_reverse;
839 
840  public:
841 
842  explicit
843  hit_rate_comparator(bool reverse)
844  :
845  m_reverse(reverse)
846  {}
847 
848  bool operator ()(mon_channel const& first, mon_channel const& second)
849  {
850  return m_reverse
851  ? first.mean() < second.mean()
852  : first.mean() > second.mean();
853  }
854 };
855 
857 {
858  bool m_reverse;
859 
860  public:
861 
862  explicit
863  run_number_comparator(bool reverse)
864  :
865  m_reverse(reverse)
866  {}
867 
868  bool operator ()(mon_channel const& first, mon_channel const& second)
869  {
870  return m_reverse
871  ? first.run_number() < second.run_number()
872  : first.run_number() > second.run_number();
873  }
874 };
875 
877 {
878  bool m_reverse;
879 
880  public:
881 
882  explicit
883  name_comparator(bool reverse)
884  :
885  m_reverse(reverse)
886  {}
887 
888  bool operator ()(mon_channel const& first, mon_channel const& second)
889  {
890  return m_reverse
891  ? first.name() < second.name()
892  : first.name() > second.name();
893  }
894 };
895 
897 {
899 
900  bool belongs(mon_channel const& ch)
901  {
903  for (
904  citer it = m_matching->begin(), et = m_matching->end()
905  ; it != et
906  ; ++it
907  ) {
908  if ((*(*it)).domid() == ch.domid()) {
909  return true;
910  }
911  }
912 
913  return false;
914  }
915 
916  public:
917 
919  std::list<ChList::const_iterator> const& matching
920  ) : m_matching(&matching)
921  {}
922 
923  bool operator ()(mon_channel const& first, mon_channel const& second)
924  {
925  bool const first_matches = belongs(first);
926  bool const second_matches = belongs(second);
927 
928  return first_matches || !second_matches;
929  }
930 };
931 
932 void Screen::sort_channels()
933 {
934  switch (sort) {
935  case kDOMID:
936  m_list.sort(domid_comparator(m_sort_reverse));
937  break;
938  case kLAST_VIEW:
939  m_list.sort(last_view_comparator(m_sort_reverse));
940  break;
941  case kRATE:
942  m_list.sort(hit_rate_comparator(m_sort_reverse));
943  break;
944  case kRUNNO:
945  m_list.sort(run_number_comparator(m_sort_reverse));
946  break;
947  case kNAME:
948  m_list.sort(name_comparator(m_sort_reverse));
949  break;
950  default:
951  assert(!"Sort internal error");
952  }
953 
954  if (m_matching_first && !m_smatched.empty() && go_match != NONE) {
955  m_list.sort(match_comparator(m_smatched));
956  }
957 }
958 
959 void print_table_head(WINDOW* win, int offset)
960 {
961  static const char head[] =
962  "DOMID MAC ADDRESS Name Run # Hit rate (min, max, avg) Last viewed S Delta time";
963 
964  if (static_cast<int>(strlen(head)) > offset) {
965  int const max_in_string = strlen(head) - offset;
966  int const nchars = std::min(COLS - 4, max_in_string);
967  wprintw(win, "%.*s", nchars, head + offset);
968  }
969 }
970 
972  WINDOW* win
973  , ChList::const_iterator const& it
974  , std::vector<char>& buffer
975  , int line_size
976  , int offset
977  , bool highlight
978 ) {
979  assert(offset <= line_size);
980 
981  int const last_view = boost::chrono::duration_cast<boost::chrono::seconds>(
982  it->last_view()
983  ).count();
984 
985  int const size = snprintf(
986  &buffer.front(),
987  line_size,
988  "%-9d %-17s %-8s %-6u %7.2f, %7.2f, %7.2f kHz %4d sec ago %s %ld ms",
989  it->domid(),
990  it->mac_address().c_str(),
991  it->name().c_str(),
992  it->run_number(),
993  it->min() / 100.,
994  it->max() / 100.,
995  it->mean() / 100.,
996  last_view,
997  it->syncd() ? "*" : " ",
998  it->avg_delta_time());
999 
1000  if (offset < std::min(line_size, size)) {
1001  if (highlight) {
1002  wattron(win, A_REVERSE);
1003  } else {
1004  wattroff(win, A_REVERSE);
1005  }
1006 
1007  if (!it->syncd()) {
1008  wattron(win, NOSYNC);
1009  }
1010 
1011  if (it->mean() > default_hit_counter_threshold) {
1012  wattron(win, HIRATE);
1013  }
1014 
1015  if (last_view > 2) {
1016  wattron(win, NODATA);
1017  }
1018 
1019  wprintw(win, "%s", &buffer[offset]);
1020 
1021  if (size > line_size) {
1022  wprintw(win, "$");
1023  }
1024  }
1025 
1026  wattrset(win, GROUND);
1027 }
1028 
1030  WINDOW* win,
1031  UTCTime const& tstamp,
1032  std::vector<char>& buffer,
1033  int line_size,
1034  int offset,
1035  bool validity)
1036 {
1037  assert(offset <= line_size);
1038 
1039  std::ostringstream oss;
1040 
1041  oss << UTCTime_h(tstamp, validity);
1042 
1043  int const size = snprintf(
1044  &buffer.front(),
1045  line_size,
1046  "Sec: %d, Tic: %-8d - %s",
1047  tstamp.sec(),
1048  tstamp.tics(),
1049  oss.str().c_str());
1050 
1051  if (offset < std::min(line_size, size)) {
1052  wprintw(win, "%s", &buffer[offset]);
1053 
1054  if (size > line_size) {
1055  wprintw(win, "$");
1056  }
1057  }
1058 }
1059 
1060 } // ns gui
Auxiliary data structure for alignment of data.
Definition: JManip.hh:296
bool belongs(mon_channel const &ch)
Definition: gui.cpp:900
domid_comparator(bool reverse)
Definition: gui.cpp:802
bool operator()(mon_channel const &first, mon_channel const &second)
Definition: gui.cpp:827
then fatal No hydrophone data file $HYDROPHONE_TXT fi sort gr k
void async_win_resize(boost::asio::signal_set &window_resize, gui::Screen &screen, boost::system::error_code const &error, int signum)
Definition: gui.cpp:106
bool is_problematic(mon_channel const &channel)
Definition: gui.cpp:540
std::pair< int, int > window_size()
Definition: gui.cpp:127
bool ischar(int key)
Definition: gui.cpp:43
uint32_t domIdentifier() const
uint32_t sec() const
Definition: utctime.hh:17
std::list< ChList::const_iterator > const * m_matching
Definition: gui.cpp:898
bool matches(mon_channel const &ch, std::string const &pattern)
Definition: gui.cpp:736
double search(const double xa, const double xb, const double xc, const JFunction1D_t &f, const int is, const double eps=1.0e-6)
Locate maximum or minimun of function.
Definition: JQuantiles.hh:48
UTCTime timeStamp() const
Auxiliary data structure for alignment of data.
Definition: JManip.hh:264
then echo The file $DIR KM3NeT_00000001_00000000 root already please rename or remove it first
static const int default_hit_counter_threshold
Definition: gui.cpp:15
then fatal Wrong number of arguments fi set_variable STRING $argv[1] set_variable DETECTOR_TXT $WORKDIR $DETECTOR_TXT tail read X Y Z RMS echo $X $Y $G1_TXT JGraph f $G1_TXT o $G1_ROOT awk BEGIN
bool operator()(mon_channel const &first, mon_channel const &second)
Definition: gui.cpp:807
bool validTimeStamp(CLBCommonHeader const &header)
then awk string
std::istream & getline(std::istream &in, JString &object)
Read string from input stream until end of line.
Definition: JString.hh:478
$WORKDIR driver txt done cat $WORKDIR driver txt<< EOFprocess ${DATAFILTER}$FILTER_HOST csh-c '(setenv ROOTSYS $ROOTSYS &&source $JPP_DIR/setenv.csh $JPP_DIR &&(JDataFilter-H\$SERVER\$-M\$LOGGER\$-d $DEBUG-u ${DATAFILTER}-P $PORT</dev/null > &/dev/null &))';process ${DATAWRITER}$WRITER_HOST csh-c '(setenv ROOTSYS $ROOTSYS &&source $JPP_DIR/setenv.csh $JPP_DIR &&(JDataWriter-H\$SERVER\$-M\$LOGGER\$-d $DEBUG-u ${DATAWRITER}</dev/null > &/dev/null &))';print enterevent ev_init{RC_CMD}event ev_reset{RC_CMD}event ev_init{RC_CMD}event ev_configure{RC_DFLTR%<$WORKDIR/ev_configure_datafilter.txt > RC_DQSIM<$WORKDIR/ev_configure_dqsimulator.txt > RC_DWRT path
counter_type advance(counter_type &counter, const counter_type value, const counter_type limit=std::numeric_limits< counter_type >::max())
Advance counter.
run_number_comparator(bool reverse)
Definition: gui.cpp:863
match_comparator(std::list< ChList::const_iterator > const &matching)
Definition: gui.cpp:918
uint32_t tics() const
Definition: utctime.hh:22
void print_timestamp(WINDOW *win, UTCTime const &tstamp, std::vector< char > &buffer, int line_size, int offset, bool validity)
Definition: gui.cpp:1029
name_comparator(bool reverse)
Definition: gui.cpp:883
void async_cin(boost::asio::posix::stream_descriptor &keyb, char &key, gui::Screen &screen, const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: gui.cpp:68
void async_commit(boost::asio::deadline_timer &timer, gui::Screen &screen, boost::system::error_code const &error)
Definition: gui.cpp:50
hit_rate_comparator(bool reverse)
Definition: gui.cpp:843
bool filter(const JDAQEvent &tev, const JEvt &evt, const Evt *const pE)
Event selection.
data_type v[N+1][M+1]
Definition: JPolint.hh:866
void print_chan(WINDOW *win, ChList::const_iterator const &it, std::vector< char > &buffer, int line_size, int offset, bool highlight)
Definition: gui.cpp:971
void print_table_head(WINDOW *win, int offset)
Definition: gui.cpp:959
last_view_comparator(bool reverse)
Definition: gui.cpp:822