discover_window.cc
Go to the documentation of this file.
1 /*
2  * Roboception GmbH
3  * Munich, Germany
4  * www.roboception.com
5  *
6  * Copyright (c) 2024 Roboception GmbH
7  * All rights reserved
8  *
9  * Author: Heiko Hirschmueller
10  */
11 
12 #include "discover_window.h"
13 
14 #include "menu_bar.h"
15 #include "help_window.h"
16 #include "about_dialog.h"
17 #include "reset_window.h"
18 #include "set_tmp_ip_window.h"
19 #include "reconnect_window.h"
20 #include "label.h"
21 #include "layout.h"
22 
23 #include "rcdiscover/discover.h"
24 #include "rcdiscover/ping.h"
25 
26 #include <FL/fl_draw.H>
27 #include <FL/fl_ask.H>
28 #include <FL/Enumerations.H>
29 #include <FL/Fl_Group.H>
30 #include <FL/Fl_Menu_Item.H>
31 
32 #ifdef WIN32
33 #include <Windows.h>
34 #undef min
35 #undef max
36 #endif
37 
38 #include <sstream>
39 #include <iomanip>
40 #include <chrono>
41 #include <iostream>
42 
43 namespace
44 {
45 
46 void quitCb(Fl_Widget *, void *user_data)
47 {
48  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
49  win->doClose();
50 }
51 
52 void helpCb(Fl_Widget *, void *)
53 {
54  HelpWindow::showWindow("discovery");
55 }
56 
57 void aboutCb(Fl_Widget *, void *)
58 {
59  AboutDialog about;
60  about.show();
61  while (about.shown()) Fl::wait();
62 }
63 
64 void discoverCb(Fl_Widget *, void *user_data)
65 {
66  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
67  win->doDiscover();
68 }
69 
70 void onlyRCCb(Fl_Widget *, void *user_data)
71 {
72  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
73  win->doOnlyRC();
74 }
75 
76 void filterCb(Fl_Widget *, void *user_data)
77 {
78  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
79  win->doFilter();
80 }
81 
82 template <int n> void copyToClipboardCb(Fl_Widget *, void *user_data)
83 {
84  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
85  win->doCopyToClipboard(n);
86 }
87 
88 void openWebGUICb(Fl_Widget *, void *user_data)
89 {
90  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
91  win->doOpenWebGUI();
92 }
93 
94 void listCb(Fl_Widget *, void *user_data)
95 {
96  if (Fl::event_button() == FL_RIGHT_MOUSE && Fl::event() == FL_PUSH)
97  {
98  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
99  win->doOpenContextMenu();
100  }
101 }
102 
103 void listSelectionChangeCb(Fl_Widget *, void *user_data)
104 {
105  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
106  win->update();
107 }
108 
109 void resetCb(Fl_Widget *, void *user_data)
110 {
111  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
112  win->doReset();
113 }
114 
115 void setTmpIPCb(Fl_Widget *, void *user_data)
116 {
117  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
118  win->doSetTmpIP();
119 }
120 
121 void reconnectCb(Fl_Widget *, void *user_data)
122 {
123  DiscoverWindow *win=reinterpret_cast<DiscoverWindow *>(user_data);
124  win->doReconnect();
125 }
126 
127 }
128 
129 DiscoverWindow::DiscoverWindow(int ww, int hh, int _only_rc, const std::string &_filter) :
130  Fl_Double_Window(1180, 394, "rcdiscover")
131 {
132  running=false;
133  discover_thread=0;
134 
135  int width=1180-2*GAP_SIZE;
136  int row_height=28;
137 
138  menu_bar=new MenuBar(0, 0, width+2*GAP_SIZE, row_height);
139  menu_bar->add("File/Quit", FL_CTRL+'q', quitCb, this);
140  menu_bar->add("Help/Help", FL_F+1, helpCb, this);
141  menu_bar->add("Help/About", 0, aboutCb, this);
142 
143  {
144  int xc=addBelowX();
145  int yc=addBelowY()+5;
146 
147  Fl_Group *group=new Fl_Group(xc, yc, width, row_height);
148 
149  discover=new Button(xc, yc, 160, row_height, "Rerun discovery");
150  discover->callback(discoverCb, this);
151 
152  Label *divider=new Label(addRightX()+20, addRightY(), 25, row_height, "|");
153  divider->textcolor(FL_INACTIVE_COLOR);
154 
155  only_rc=new Fl_Check_Button(ADD_RIGHT_XY, 150, row_height, "Only rc_...devices");
156  only_rc->value(_only_rc);
157  only_rc->callback(onlyRCCb, this);
158 
159  filter=new InputFilter(addRightX()+40, addRightY(), 150, row_height, "Filter");
160  filter->value(_filter.c_str());
161  filter->setChangeCallback(filterCb, this);
162 
163  Fl_Group *empty=new Fl_Group(ADD_RIGHT_XY, width-5*GAP_SIZE-(160+45+150+190+row_height), row_height);
164  empty->end();
165  group->resizable(empty);
166 
167  logo=new Logo(ADD_RIGHT_XY, row_height, row_height);
168 
169  group->end();
170  }
171 
172  {
173  int xc=addBelowX();
174  int yc=addBelowY()+5;
175 
176  // invisible context menu "button" at the same area as device list
177  context_menu=new Fl_Menu_Button(xc, yc, 0, 0);
178  context_menu->type(Fl_Menu_Button::POPUP3);
179 
180  context_menu->add("Copy name", 0, copyToClipboardCb<0>, this);
181  context_menu->add("Copy manufacturer", 0, copyToClipboardCb<1>, this);
182  context_menu->add("Copy model", 0, copyToClipboardCb<2>, this);
183  context_menu->add("Copy serial number", 0, copyToClipboardCb<3>, this);
184  context_menu->add("Copy IP address", 0, copyToClipboardCb<4>, this);
185  context_menu->add("Copy MAC address", 0, copyToClipboardCb<5>, this);
186  context_menu->add("Copy interface(s)", 0, copyToClipboardCb<6>, this, FL_MENU_DIVIDER);
187  context_menu->add("Open WebGUI", 0, openWebGUICb, this, FL_MENU_DIVIDER);
188  context_menu->add("Reset rc_visard", 0, resetCb, this);
189  context_menu->add("Set temporary IP address", 0, setTmpIPCb, this);
190  context_menu->add("Reconnect device", 0, reconnectCb, this);
191 
192  openwebgui_index=context_menu->find_index("Open WebGUI");
193  reset_index=context_menu->find_index("Reset rc_visard");
194 
195  // device list
196  list=new DeviceList(xc, yc, width, 260);
197  list->callback(listCb, this);
198  list->setSelectionChangeCallback(listSelectionChangeCb, this);
199 
200  resizable(list);
201  }
202 
203  {
204  int xc=addBelowX();
205  int yc=addBelowY();
206 
207  Fl_Group *group=new Fl_Group(addBelowX(), addBelowY()+5, width, row_height);
208 
209  reset=new Button(xc, yc, 180, row_height, "Reset rc_visard");
210  reset->callback(resetCb, this);
211 
212  set_tmp_ip=new Button(ADD_RIGHT_XY, 200, row_height, "Set temporary IP address");
213  set_tmp_ip->callback(setTmpIPCb, this);
214 
215  reconnect=new Button(ADD_RIGHT_XY, 180, row_height, "Reconnect device");
216  reconnect->callback(reconnectCb, this);
217 
218  Fl_Group *empty=new Fl_Group(ADD_RIGHT_XY, width-4*GAP_SIZE-(180+200+180+30), row_height);
219  empty->end();
220  group->resizable(empty);
221 
222  help=new Button(ADD_RIGHT_XY, row_height, row_height, "?");
223  help->callback(helpCb, this);
224 
225  group->end();
226  }
227 
228  callback(quitCb, this);
229 
230 // checkGroupSize(__func__);
231  end();
232 
233  size_range(std::min(w(), 640), std::min(h(), 200));
234 
235  list->filterRCDevices(_only_rc != 0);
236  list->filter(_filter.c_str());
237 
238  update();
239 
240  size(ww, hh);
241 }
242 
244 {
245  running=false;
246 
247  if (discover_thread)
248  {
249  discover_thread->join();
250  delete discover_thread;
251  }
252 }
253 
255 {
256  running=false;
257 
258  if (discover_thread)
259  {
260  discover_thread->join();
261  delete discover_thread;
262  discover_thread=0;
263  }
264 
265  running=true;
266  discover_thread=new std::thread(&DiscoverWindow::discoverThread, this);
267 
268  update();
269 }
270 
272 {
273  list->filterRCDevices(only_rc->value() != 0);
274  update();
275 }
276 
278 {
279  list->filter(filter->value());
280  update();
281 }
282 
284 {
285  if (list->callback_context() == Fl_Table::CONTEXT_CELL)
286  {
287  // right click is used to open context menu
288 
289  list->select_row(list->callback_row());
290  update();
291 
292  // enable or disable some menu items depending on selection
293 
295  {
296  // const cast is ok since menu item has been created dynamically
297  const_cast<Fl_Menu_Item *>(&context_menu->menu()[openwebgui_index])->activate();
298  }
299  else
300  {
301  const_cast<Fl_Menu_Item *>(&context_menu->menu()[openwebgui_index])->deactivate();
302  }
303 
304  if (list->isRCVisardSelected())
305  {
306  // const cast is ok since menu item has been created dynamically
307  const_cast<Fl_Menu_Item *>(&context_menu->menu()[reset_index])->activate();
308  }
309  else
310  {
311  const_cast<Fl_Menu_Item *>(&context_menu->menu()[reset_index])->deactivate();
312  }
313 
314  // show context menu at current mouse pointer position
315 
316  context_menu->position(Fl::event_x(), Fl::event_y());
317  context_menu->show();
318  context_menu->popup();
319  }
320  else
321  {
322  list->select_row(0, 0);
323  }
324 }
325 
327 {
328  int r=list->getSelectedRow();
329 
330  if (r >= 0)
331  {
332  std::string value=list->getCell(r, i);
333  Fl::copy(value.c_str(), static_cast<int>(value.size()), 1);
334  }
335 }
336 
338 {
339  int r=list->getSelectedRow();
340  list->openWebGUI(r);
341 }
342 
344 {
345  std::string mac=list->getSelectedMAC();
346 
347  if (list->isRCVisardSelected() || mac.size() == 0)
348  {
350  win->updateDevices(list->getCurrentNameMACList(true), mac);
351  }
352 }
353 
355 {
358 }
359 
361 {
364 }
365 
367 {
368  if (!running)
369  {
370  hide();
371  }
372 
377 }
378 
380 {
381  if (list->isRCVisardSelected() || list->getSelectedMAC().size() == 0)
382  {
383  reset->activate();
384  }
385  else
386  {
387  reset->deactivate();
388  }
389 
390  if (running)
391  {
392  discover->deactivate();
393  logo->startSpinning();
394  }
395  else
396  {
397  discover->activate();
398  logo->stopSpinning();
399  }
400 
401  redraw();
402 }
403 
405 {
406  try
407  {
408  // clear list and update to deactive discover button
409 
410  Fl::lock();
411  list->clear();
412  update();
413  Fl::unlock();
414  Fl::awake();
415 
416  // broadcast discovery request
417 
419  discover.broadcastRequest();
420 
421  // collecting answers
422 
423  std::chrono::steady_clock::time_point tstart=std::chrono::steady_clock::now();
424  std::chrono::steady_clock::time_point tend=tstart;
425 
426  std::vector<rcdiscover::DeviceInfo> info;
427 
428  while (running && (discover.getResponse(info, 100) ||
429  std::chrono::duration<double, std::milli>(tend-tstart).count() < 1000))
430  {
431  // add answers immediately to table
432 
433  Fl::lock();
434 
435  for (size_t k=0; k<info.size(); k++)
436  {
437  if (info[k].isValid())
438  {
439  std::ostringstream ip, mac;
440 
441  ip << ((info[k].getIP()>>24)&0xff) << '.' << ((info[k].getIP()>>16)&0xff) << '.' <<
442  ((info[k].getIP()>>8)&0xff) << '.' << (info[k].getIP()&0xff);
443 
444  mac << std::hex << std::setw(2) << std::setfill('0') <<
445  std::setw(2) << std::setfill('0') << ((info[k].getMAC()>>40)&0xff) << ':' <<
446  std::setw(2) << std::setfill('0') << ((info[k].getMAC()>>32)&0xff) << ':' <<
447  std::setw(2) << std::setfill('0') << ((info[k].getMAC()>>24)&0xff) << ':' <<
448  std::setw(2) << std::setfill('0') << ((info[k].getMAC()>>16)&0xff) << ':' <<
449  std::setw(2) << std::setfill('0') << ((info[k].getMAC()>>8)&0xff) << ':' <<
450  std::setw(2) << std::setfill('0') << (info[k].getMAC()&0xff);
451 
452  list->add(info[k].getUserName().c_str(),
453  info[k].getManufacturerName().c_str(),
454  info[k].getModelName().c_str(),
455  info[k].getSerialNumber().c_str(),
456  ip.str().c_str(),
457  mac.str().c_str(),
458  info[k].getIfaceName().c_str(),
459  checkReachabilityOfSensor(info[k]));
460  }
461  }
462 
463  update();
464  Fl::unlock();
465  Fl::awake();
466 
467  info.clear();
468  tend=std::chrono::steady_clock::now();
469  }
470  }
471  catch (const std::exception &ex)
472  {
473  // this should never happen, but goes to std error instead of opening an
474  // error dialog, because we are working in a background thread
475 
476  std::cerr << "Exception in discover thread: " << ex.what() << std::endl;
477  }
478  catch (...)
479  {
480  // this should never happen, but goes to std error instead of opening an
481  // error dialog, because we are working in a background thread
482 
483  std::cerr << "Unknown exception in discover thread" << std::endl;
484  }
485 
486  // leaving discover thread and update to activate discover button
487 
488  Fl::lock();
489  running=false;
490  update();
491  Fl::unlock();
492  Fl::awake();
493 }
DiscoverWindow::only_rc
Fl_Check_Button * only_rc
Definition: discover_window.h:68
MenuBar
Definition: menu_bar.h:18
DeviceList::setSelectionChangeCallback
void setSelectionChangeCallback(Fl_Callback *_cb, void *p)
Definition: device_list.h:33
DiscoverWindow::doCopyToClipboard
void doCopyToClipboard(int i)
Definition: discover_window.cc:326
Logo
Definition: logo.h:19
ReconnectWindow
Definition: reconnect_window.h:25
InputFilter::setChangeCallback
void setChangeCallback(Fl_Callback *_cb, void *p)
Definition: input_filter.h:26
HelpWindow::hideWindow
static void hideWindow()
Definition: help_window.cc:43
DiscoverWindow::doReset
void doReset()
Definition: discover_window.cc:343
DiscoverWindow::DiscoverWindow
DiscoverWindow(int ww, int hh, int _only_rc, const std::string &_filter)
Definition: discover_window.cc:129
DiscoverWindow::set_tmp_ip
Button * set_tmp_ip
Definition: discover_window.h:76
Button
Definition: button.h:18
DeviceList::isReachableRCDeviceSelected
bool isReachableRCDeviceSelected()
Definition: device_list.cc:178
discover.h
ReconnectWindow::updateDevices
void updateDevices(const std::vector< std::pair< std::string, std::string > > &list, const std::string &sel_mac)
Definition: reconnect_window.cc:79
discover_window.h
DiscoverWindow::update
void update()
Definition: discover_window.cc:379
ResetWindow::showWindow
static ResetWindow * showWindow()
Definition: reset_window.cc:79
ReconnectWindow::hideWindow
static void hideWindow()
Definition: reconnect_window.cc:71
ReconnectWindow::showWindow
static ReconnectWindow * showWindow()
Definition: reconnect_window.cc:59
reconnect_window.h
SetTmpIPWindow
Definition: set_tmp_ip_window.h:26
DiscoverWindow::discover
Button * discover
Definition: discover_window.h:67
DeviceList::clear
void clear()
Definition: device_list.cc:59
menu_bar.h
ping.h
DiscoverWindow::filter
InputFilter * filter
Definition: discover_window.h:69
DiscoverWindow::context_menu
Fl_Menu_Button * context_menu
Definition: discover_window.h:72
DiscoverWindow::doSetTmpIP
void doSetTmpIP()
Definition: discover_window.cc:354
ADD_RIGHT_XY
#define ADD_RIGHT_XY
Definition: layout.h:120
DiscoverWindow::help
Button * help
Definition: discover_window.h:78
ResetWindow::updateDevices
void updateDevices(const std::vector< std::pair< std::string, std::string > > &list, const std::string &sel_mac)
Definition: reset_window.cc:99
AboutDialog
Definition: about_dialog.h:21
DeviceList::filter
void filter(const char *filter_value)
Definition: device_list.cc:259
reset_window.h
DiscoverWindow::doOpenWebGUI
void doOpenWebGUI()
Definition: discover_window.cc:337
DiscoverWindow::doClose
void doClose()
Definition: discover_window.cc:366
GAP_SIZE
#define GAP_SIZE
Definition: layout.h:21
SetTmpIPWindow::updateDevices
void updateDevices(const std::vector< std::pair< std::string, std::string > > &list, const std::string &sel_mac)
Definition: set_tmp_ip_window.cc:97
DeviceList::openWebGUI
void openWebGUI(int r)
Definition: device_list.cc:228
DiscoverWindow::doOnlyRC
void doOnlyRC()
Definition: discover_window.cc:271
DeviceList::add
void add(const char *name, const char *manufacturer, const char *model, const char *sn, const char *ip, const char *mac, const char *interface, bool reachable)
Definition: device_list.cc:79
Logo::startSpinning
void startSpinning()
Definition: logo.cc:55
DeviceList::getSelectedRow
int getSelectedRow()
Definition: device_list.cc:164
about_dialog.h
addRightY
int addRightY(int gap=GAP_SIZE)
Computes the y coordinate of a widget to the right of the last added widget.
Definition: layout.h:43
DeviceList
Definition: device_list.h:22
DiscoverWindow::doReconnect
void doReconnect()
Definition: discover_window.cc:360
DiscoverWindow::menu_bar
MenuBar * menu_bar
Definition: discover_window.h:65
DiscoverWindow::~DiscoverWindow
~DiscoverWindow()
Definition: discover_window.cc:243
addRightX
int addRightX(int gap=GAP_SIZE)
Computes the x coordinate of a widget to the right of the last added widget.
Definition: layout.h:27
rcdiscover::Discover
Definition: discover.h:50
DiscoverWindow::reset_index
int reset_index
Definition: discover_window.h:74
DeviceList::isRCVisardSelected
bool isRCVisardSelected()
Definition: device_list.cc:185
DeviceList::getCell
std::string getCell(int r, int c)
Definition: device_list.cc:218
DiscoverWindow::running
std::atomic_bool running
Definition: discover_window.h:62
DiscoverWindow::doFilter
void doFilter()
Definition: discover_window.cc:277
label.h
rcdiscover::checkReachabilityOfSensor
bool checkReachabilityOfSensor(const DeviceInfo &info)
Check whether an device is reachable via ICMP.
Definition: ping.cc:93
DiscoverWindow::discover_thread
std::thread * discover_thread
Definition: discover_window.h:63
DeviceList::getCurrentNameMACList
std::vector< std::pair< std::string, std::string > > getCurrentNameMACList(bool only_rc_visard)
Definition: device_list.cc:203
help_window.h
DeviceList::filterRCDevices
void filterRCDevices(bool filter_rc)
Definition: device_list.cc:249
DiscoverWindow::list
DeviceList * list
Definition: discover_window.h:71
layout.h
Label
Definition: label.h:18
DiscoverWindow::reconnect
Button * reconnect
Definition: discover_window.h:77
addBelowX
int addBelowX(int gap=GAP_SIZE)
Computes the x coordinate of a widget in the next line.
Definition: layout.h:59
DiscoverWindow::openwebgui_index
int openwebgui_index
Definition: discover_window.h:73
ResetWindow::hideWindow
static void hideWindow()
Definition: reset_window.cc:91
DiscoverWindow::doDiscover
void doDiscover()
Definition: discover_window.cc:254
addBelowY
int addBelowY(int gap=GAP_SIZE)
Computes the y coordinate of a widget to the next line.
Definition: layout.h:68
DeviceList::getSelectedMAC
std::string getSelectedMAC()
Definition: device_list.cc:191
Logo::stopSpinning
void stopSpinning()
Definition: logo.cc:66
DiscoverWindow::doOpenContextMenu
void doOpenContextMenu()
Definition: discover_window.cc:283
SetTmpIPWindow::showWindow
static SetTmpIPWindow * showWindow()
Definition: set_tmp_ip_window.cc:77
DiscoverWindow::logo
Logo * logo
Definition: discover_window.h:70
ResetWindow
Definition: reset_window.h:22
DiscoverWindow
Definition: discover_window.h:32
SetTmpIPWindow::hideWindow
static void hideWindow()
Definition: set_tmp_ip_window.cc:89
InputFilter
Definition: input_filter.h:20
DiscoverWindow::discoverThread
void discoverThread()
Definition: discover_window.cc:404
set_tmp_ip_window.h
DiscoverWindow::reset
Button * reset
Definition: discover_window.h:75
HelpWindow::showWindow
static void showWindow(const char *target=0)
Definition: help_window.cc:28


rcdiscover
Author(s): Heiko Hirschmueller , Raphael Schaller
autogenerated on Thu Aug 1 2024 02:55:56