5 #include <boost/bind.hpp>
7 #include <boost/ref.hpp>
17 std::string mon_channel::mac_address()
const
24 std::ostringstream oss(
"0800", std::ostringstream::ate);
25 oss << std::hex << domid();
26 if (oss.tellp() != 12) {
30 std::ostringstream stream;
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 ?
":" :
"");
46 key >= std::numeric_limits<char>::min()
47 && key <= std::numeric_limits<char>::max();
51 boost::asio::deadline_timer& timer,
53 boost::system::error_code
const& error)
58 timer.expires_from_now(boost::posix_time::seconds(1));
64 boost::asio::placeholders::error));
69 boost::asio::posix::stream_descriptor& keyb,
72 const boost::system::error_code& error,
73 std::size_t bytes_transferred)
79 boost::asio::posix::stream_descriptor::bytes_readable command(
true);
80 keyb.io_control(command);
82 std::size_t nbytes = command.get();
85 boost::system::error_code ec;
86 keyb.read_some(boost::asio::buffer(&key,
sizeof(key)), ec);
95 boost::asio::buffer(&key,
sizeof(key)),
101 boost::asio::placeholders::error,
102 boost::asio::placeholders::bytes_transferred));
107 boost::asio::signal_set& window_resize,
109 boost::system::error_code
const& error,
115 screen.resize(win_size.first, win_size.second);
117 window_resize.async_wait(
120 boost::ref(window_resize),
122 boost::asio::placeholders::error,
123 boost::asio::placeholders::signal_number));
131 ioctl(0, TIOCGWINSZ, &sz);
133 return std::make_pair(sz.ws_row, sz.ws_col);
138 std::string
const Screen::search_prompt =
"Search: ";
139 std::string
const Screen::regex_prompt =
"RegEx: ";
141 void LineEdit::move(LineEdit::movement dir)
145 m_current_pos -= m_current_pos == 0 ? 0 : 1;
148 m_current_pos += m_current_pos == m_current_line.size() ? 0 : 1;
154 m_current_pos = m_current_line.size();
157 if (not m_history.empty()) {
158 if (m_history_pos == m_history.size()) {
159 m_editing_line.swap(m_current_line);
162 if (m_history_pos != 0) {
168 m_current_line = *it;
169 m_current_pos = m_current_line.size();
174 if (not m_history.empty()) {
175 if (m_history_pos == m_history.size() - 1) {
176 m_editing_line.swap(m_current_line);
178 m_current_pos = m_current_line.size();
179 }
else if (m_history_pos < m_history.size()) {
185 m_current_line = *it;
186 m_current_pos = m_current_line.size();
193 void LineEdit::load_history(std::string
const& path)
195 std::ifstream ifs(path.c_str());
197 while (ifs && ifs.peek() != EOF) {
201 m_history.push_back(line);
205 void LineEdit::store_history(std::string
const& path)
const
207 std::ofstream ofs(path.c_str());
210 citer it = m_history.begin(), et = m_history.end()
218 void Screen::elaborate(
int key)
220 if (status != kSEARCH && status != kREGEX) {
234 }
else if (key ==
'c') {
239 }
else if (key ==
't') {
242 }
else if (key ==
'd') {
245 }
else if (key ==
'r') {
248 }
else if (key ==
'n') {
251 }
else if (key ==
'l') {
254 }
else if (key ==
'i') {
255 m_sort_reverse = !m_sort_reverse;
257 }
else if (key ==
'g') {
265 }
else if (key ==
'G') {
267 m_selected = m_list.size() - 1;
273 }
else if (key ==
'/') {
275 m_search_editor.reset();
276 update_bar(search_prompt, m_search_editor);
277 }
else if (key ==
'%') {
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;
284 if (m_matching_first) {
285 write_to_status_bar(
"Grouping matching CLBs on top");
287 write_to_status_bar(
"Grouping disabled");
289 }
else if (key ==
'w') {
292 }
else if (key == kKEY_ENTER) {
299 }
else if (key == kKEY_DOWN) {
302 m_selected + 1 ==
static_cast<int>(m_list.size())
310 }
else if (key == kKEY_UP) {
321 }
else if (key == kKEY_LEFT) {
326 }
else if (key == kKEY_RIGHT) {
327 if (m_offset + COLS + 1 < max_line_size) {
332 status_unrecognised(key);
336 if (key == kKEY_ESC) {
340 status_unrecognised(key);
344 if (key == kKEY_ESC) {
347 }
else if (key == kKEY_DOWN) {
350 m_selected + 1 ==
static_cast<int>(m_list.size())
358 }
else if (key == kKEY_UP) {
370 status_unrecognised(key);
374 if (key == kKEY_ESC) {
377 if (!m_search_editor.current().empty()) {
378 m_search_editor.add_history();
385 }
else if (key == kKEY_ENTER) {
387 m_search_editor.add_history();
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) {
397 }
else if (key == kKEY_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);
414 update_bar(search_prompt, m_search_editor);
419 if (key == kKEY_ESC) {
423 }
else if (key == kKEY_ENTER) {
424 if (!m_regex_editor.current().empty()) {
425 m_regex_editor.add_history();
428 std::string
const current_line = m_regex_editor.current();
429 m_regex_editor.reset();
434 m_regex.assign(current_line, boost::regex_constants::icase);
438 write_to_status_bar(
"Invalid regex");
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) {
449 }
else if (key == kKEY_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);
466 update_bar(regex_prompt, m_regex_editor);
469 assert(!
"Internal screen error");
473 void Screen::update_bar(std::string
const& prompt, LineEdit
const& le)
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);
483 void Screen::show_help()
const
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);
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());
535 wnoutrefresh(help_win);
545 || boost::chrono::duration_cast<boost::chrono::seconds>(channel.last_view())
546 > boost::chrono::seconds(2);
549 void Screen::write_head()
const
551 bool const problematic = std::find_if(
560 if (m_smatched.empty()) {
563 ,
"CLBSK - %s - # CLBs:%c %d - 'q' to quit, 'h' for help"
565 , problematic ?
'!' :
' '
571 ,
"CLBSK - %s - # CLBs:%c %d (%d) - 'q' to quit, 'h' for help"
573 , problematic ?
'!' :
' '
579 wnoutrefresh(m_hwin);
583 void Screen::write_page()
588 mvwaddstr(m_cwin, 0, 3,
"^");
591 if (m_lower < static_cast<int>(m_list.size())) {
592 mvwaddstr(m_cwin, LINES - 3, 3,
"v");
599 typedef ChList::const_iterator citerator;
601 citerator it = m_list.begin(), et = m_list.end();
604 for (
int vcount = m_upper; it != et && vcount < m_lower; ++vcount, ++it) {
605 wmove(m_cwin, ++count, 2);
610 , COLS + m_offset - 3
612 , std::find(m_smatched.begin(), m_smatched.end(), it) != m_smatched.end()
615 if (count - 2 == m_selected - m_upper) {
616 mvwaddstr(m_cwin, count, 1,
">");
619 wnoutrefresh(m_cwin);
623 void Screen::move_limits()
625 if (m_upper > m_selected) {
626 m_upper = m_selected;
627 m_lower = m_upper + LINES - 5;
629 if (m_lower <= m_selected) {
630 m_lower = m_selected + 1;
631 m_upper = m_lower - LINES + 5;
637 ChList::const_iterator it = m_list.begin();
644 wprintw(m_cwin,
"Press ESC to return back.");
649 print_chan(m_cwin, it, m_linebuffer, COLS - 3, 0,
false);
651 uint32_t
const*
const data =
static_cast<uint32_t const*
>(
652 static_cast<void const*
>(header + 1));
668 for (
int i = 0; i < 31; ++i) {
669 wprintw(m_cwin,
"CH%02d: %5d", i, ntohl(data[i]));
675 wmove(m_cwin, y + 1, 2);
677 wmove(m_cwin, y, x + 2);
684 char const*
const raw_data =
static_cast<char const*
>(
685 static_cast<void const*
>(header));
687 SCData
const*
const scdata =
static_cast<SCData const*
>(
688 static_cast<void const*
>(
689 raw_data +
sizeof(*header) + 31 *
sizeof(uint32_t)));
691 wmove(m_cwin, y + 2, 2);
692 wprintw(m_cwin,
"Validity: 0x%x", ntohl(scdata->valid));
694 wmove(m_cwin, y + 3, 2);
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));
702 wmove(m_cwin, y + 4, 2);
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));
710 wmove(m_cwin, y + 5, 2);
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));
718 wmove(m_cwin, y + 6, 2);
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));
725 wmove(m_cwin, y + 7, 2);
726 wprintw(m_cwin,
"Temperature: %.2f Celsius", ntohs(scdata->temp) / 100.);
728 wmove(m_cwin, y + 8, 2);
729 wprintw(m_cwin,
"Humidity: %.2f RH", ntohs(scdata->humidity) / 100.);
731 wnoutrefresh(m_cwin);
736 bool matches(mon_channel
const& ch, std::string
const& pattern)
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
752 ChList::const_iterator it = m_list.begin(), et = m_list.end()
756 if (
matches(*it, m_search_editor.current())) {
757 m_smatched.push_back(it);
762 bool matches(mon_channel
const& ch, boost::regex
const& regex)
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);
770 void Screen::filter()
775 ChList::const_iterator it = m_list.begin(), et = m_list.end()
780 m_smatched.push_back(it);
785 bool Screen::is_filter()
const
787 return status == kSINGLE;
790 bool Screen::is_user_input()
const
792 return status >= kSEARCH;
807 bool operator ()(mon_channel
const& first, mon_channel
const& second)
810 ? first.domid() < second.domid()
811 : first.domid() > second.domid();
827 bool operator ()(mon_channel
const& first, mon_channel
const& second)
829 using namespace boost::chrono;
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());
848 bool operator ()(mon_channel
const& first, mon_channel
const& second)
851 ? first.mean() < second.mean()
852 : first.mean() > second.mean();
868 bool operator ()(mon_channel
const& first, mon_channel
const& second)
871 ? first.run_number() < second.run_number()
872 : first.run_number() > second.run_number();
888 bool operator ()(mon_channel
const& first, mon_channel
const& second)
891 ? first.name() < second.name()
892 : first.name() > second.name();
904 citer it = m_matching->begin(), et = m_matching->end()
908 if ((*(*it)).domid() == ch.domid()) {
920 ) : m_matching(&matching)
923 bool operator ()(mon_channel
const& first, mon_channel
const& second)
925 bool const first_matches = belongs(first);
926 bool const second_matches = belongs(second);
928 return first_matches || !second_matches;
932 void Screen::sort_channels()
936 m_list.sort(domid_comparator(m_sort_reverse));
942 m_list.sort(hit_rate_comparator(m_sort_reverse));
945 m_list.sort(run_number_comparator(m_sort_reverse));
948 m_list.sort(name_comparator(m_sort_reverse));
951 assert(!
"Sort internal error");
954 if (m_matching_first && !m_smatched.empty() && go_match != NONE) {
955 m_list.sort(match_comparator(m_smatched));
961 static const char head[] =
962 "DOMID MAC ADDRESS Name Run # Hit rate (min, max, avg) Last viewed S Delta time";
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);
973 , ChList::const_iterator
const& it
979 assert(offset <= line_size);
981 int const last_view = boost::chrono::duration_cast<boost::chrono::seconds>(
985 int const size = snprintf(
988 "%-9d %-17s %-8s %-6u %7.2f, %7.2f, %7.2f kHz %4d sec ago %s %lld ms",
990 it->mac_address().c_str(),
997 it->syncd() ?
"*" :
" ",
998 it->avg_delta_time());
1000 if (offset < std::min(line_size, size)) {
1002 wattron(win, A_REVERSE);
1004 wattroff(win, A_REVERSE);
1008 wattron(win, NOSYNC);
1012 wattron(win, HIRATE);
1015 if (last_view > 2) {
1016 wattron(win, NODATA);
1019 wprintw(win,
"%s", &buffer[offset]);
1021 if (size > line_size) {
1026 wattrset(win, GROUND);
1037 assert(offset <= line_size);
1039 std::ostringstream oss;
1041 oss << UTCTime_h(tstamp, validity);
1043 int const size = snprintf(
1046 "Sec: %d, Tic: %-8d - %s",
1051 if (offset < std::min(line_size, size)) {
1052 wprintw(win,
"%s", &buffer[offset]);
1054 if (size > line_size) {
Auxiliary data structure for alignment of data.
bool belongs(mon_channel const &ch)
domid_comparator(bool reverse)
bool operator()(mon_channel const &first, mon_channel const &second)
void async_win_resize(boost::asio::signal_set &window_resize, gui::Screen &screen, boost::system::error_code const &error, int signum)
bool is_problematic(mon_channel const &channel)
std::pair< int, int > window_size()
std::list< ChList::const_iterator > const * m_matching
bool matches(mon_channel const &ch, std::string const &pattern)
Auxiliary data structure for alignment of data.
static const int default_hit_counter_threshold
bool operator()(mon_channel const &first, mon_channel const &second)
std::istream & getline(std::istream &in, JString &object)
Read string from input stream until end of line.
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)
match_comparator(std::list< ChList::const_iterator > const &matching)
void print_timestamp(WINDOW *win, UTCTime const &tstamp, std::vector< char > &buffer, int line_size, int offset, bool validity)
name_comparator(bool reverse)
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)
void async_commit(boost::asio::deadline_timer &timer, gui::Screen &screen, boost::system::error_code const &error)
hit_rate_comparator(bool reverse)
void print_chan(WINDOW *win, ChList::const_iterator const &it, std::vector< char > &buffer, int line_size, int offset, bool highlight)
void print_table_head(WINDOW *win, int offset)
last_view_comparator(bool reverse)