worker.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 "worker.h"
13 
14 #include "branding/branding.h"
15 
16 #include "rc_genicam_api/system.h"
17 #include "rc_genicam_api/interface.h"
18 
19 #include "check_calib.h"
20 #include "check_license.h"
21 #include "util.h"
22 
23 #include <rclic/verify.h>
24 
25 #include <Fl/fl_ask.H>
26 
27 #include <fstream>
28 
29 namespace
30 {
31 
32 bool isSupportedCamera(const std::shared_ptr<rcg::Device> &dev, const char *vendor_model[])
33 {
34  bool found=false;
35  for (size_t i=0; !found && vendor_model[i] != 0; i+=2)
36  {
37  found=(dev->getVendor() == vendor_model[i] &&
38  dev->getModel().compare(0, strlen(vendor_model[i+1]), vendor_model[i+1]) == 0);
39  }
40 
41  return found;
42 }
43 
44 }
45 
46 void discoverWorker(const std::vector<std::shared_ptr<rcg::Interface> > &ilist, DeviceList *list,
47  Fl_Text_Buffer *buffer, std::atomic_bool &running)
48 {
49  try
50  {
51  // get names and serial numbers of all connected cameras that might belong
52  // to an rc_viscore regarding vendor and model name
53 
54  const char *vendor_model[]=
55  {
56  "MATRIX VISION GmbH", "mvBlueCOUGAR",
57  "MATRIX VISION GmbH", "mvBlueFOX3",
58  "Basler", "a2A2448-23gcBAS",
59  "Basler", "a2A2448-23gmBAS",
60  0, 0
61  };
62 
63  std::vector<std::shared_ptr<rcg::Device> > devices;
64  bool multiple_interfaces=false;
65 
66  for (size_t i=0; i<ilist.size() && !multiple_interfaces; i++)
67  {
68  try
69  {
70  ilist[i]->open();
71  std::vector<std::shared_ptr<rcg::Device> > list=ilist[i]->getDevices();
72 
73  for (size_t k=0; k<list.size() && !multiple_interfaces; k++)
74  {
75  if (isSupportedCamera(list[k], vendor_model))
76  {
77  // check that serial number does not yet exist (if it does, then the
78  // camera is reachable via two interface, e.g. LAN and WLAN)
79 
80  std::string sn=list[k]->getSerialNumber();
81  for (size_t j=0; j<devices.size(); j++)
82  {
83  if (devices[j]->getSerialNumber() == sn)
84  {
85  multiple_interfaces=true;
86  break;
87  }
88  }
89 
90  devices.push_back(list[k]);
91  }
92  }
93  }
94  catch (const std::exception &ex)
95  {
96  std::ostringstream out;
97 
98  Fl::lock();
99  fl_alert("%s", ex.what());
100  Fl::unlock();
101  }
102  }
103 
104  // the user must ensure that the cameras are not reachable via multiple
105  // interfaces
106 
107  if (multiple_interfaces)
108  {
109  std::ostringstream out;
110 
111  out << "Found cameras with identical serial numbers. This indicates that ";
112  out << "cameras can be reached through different network interfaces, e.g. ";
113  out << "LAN and WLAN. Please ensure that cameras are only visible through ";
114  out << "one interface, e.g. by turning off WLAN, and try again.";
115 
116  Fl::lock();
117  buffer->text(out.str().c_str());
118  Fl::unlock();
119  }
120  else
121  {
122  // find left/right pairs according to names
123 
124  bool noaccess=false;
125  bool misconfigured=false;
126  std::vector<std::shared_ptr<rcg::Device> > all=devices;
127 
128  for (size_t i=0; i<all.size(); i++)
129  {
130  std::string lname;
131  if (all[i])
132  {
133  lname=all[i]->getUserDefinedName();
134  if (lname.size() == 0) lname=all[i]->getDisplayName();
135  }
136 
137  if (lname.size() >= 1 && lname.back() == 'L')
138  {
139  for (size_t k=0; k<all.size(); k++)
140  {
141  std::string rname;
142  if (all[k])
143  {
144  rname=all[k]->getUserDefinedName();
145  if (rname.size() == 0) rname=all[k]->getDisplayName();
146  }
147 
148  if (lname.size() == rname.size() && rname.back() == 'R' &&
149  lname.compare(0, lname.size()-1, rname, 0, lname.size()-1) == 0)
150  {
151  // check that model is exactly the same
152 
153  if (all[i]->getModel() == all[k]->getModel())
154  {
155  // check that each names are unique
156 
157  bool found=false;
158  for (size_t j=0; !found && j<all.size(); j++)
159  {
160  if (all[j] && j != i && j != k)
161  {
162  std::string name=all[j]->getUserDefinedName();
163  if (name.size() == 0) name=all[j]->getDisplayName();
164 
165  if (name == lname || name == rname)
166  {
167  found=true;
168  }
169  }
170  }
171 
172  if (!found)
173  {
174  // add rc_viscore to table
175 
176  std::shared_ptr<gutil::Properties> calib;
177 
178  std::string snleft=all[i]->getSerialNumber();
179  std::string snright=all[k]->getSerialNumber();
180  std::string calib_status=getCalibrationStatus(calib, all[i]);
181  std::string license_status=getLicenseStatus(all[i], all[k]);
182 
183  Fl::lock();
184  list->add(lname.substr(0, lname.size()-1).c_str(),
185  snleft.c_str(), snright.c_str(), calib_status.c_str(),
186  license_status.c_str(), all[i], all[k], calib);
187  Fl::unlock();
188 
189  if ((calib_status != "ok" && calib_status != "no access") ||
190  (license_status != "ok" && license_status != "no access"))
191  {
192  if ((calib_status == "no access" || calib_status == "no nodemap") &&
193  (license_status == "no access" || license_status == "no nodemap"))
194  {
195  noaccess=true;
196  }
197  else
198  {
199  misconfigured=true;
200  }
201  }
202 
203  // remove devices from list
204 
205  all[i].reset();
206  all[k].reset();
207  }
208  else
209  {
210  std::ostringstream out;
211  out << "Error: Cameras " << lname << " (" << all[i]->getSerialNumber() <<
212  ") and " << rname << " (" << all[k]->getSerialNumber() <<
213  " would match by name, but names are not unique!\n\n";
214 
215  Fl::lock();
216  buffer->text(out.str().c_str());
217  Fl::unlock();
218  }
219  }
220  else
221  {
222  std::ostringstream out;
223  out << "Error: Cameras " << lname << " (" << all[i]->getSerialNumber() <<
224  ") and " << rname << " (" << all[k]->getSerialNumber() <<
225  " would match by name, but have different model!\n\n";
226 
227  Fl::lock();
228  buffer->text(out.str().c_str());
229  Fl::unlock();
230  }
231  }
232  }
233  }
234  }
235 
236  // find cameras with license file and search for corresponding left camera
237 
238  bool wrong_name=false;
239 
240  for (size_t k=0; k<all.size(); k++)
241  {
242  if (all[k])
243  {
244  // check if camera contains license with valid signature and get SN of
245  // left camera
246 
247  std::string lsn=getLeftSNFromLicense(all[k]);
248 
249  if (lsn.size() > 0)
250  {
251  // find left camera
252 
253  for (size_t i=0; i<all.size(); i++)
254  {
255  if (all[i] && i != k && all[i]->getSerialNumber() == lsn)
256  {
257  // add rc_viscore to table
258 
259  std::shared_ptr<gutil::Properties> calib;
260 
261  std::string snleft=all[i]->getSerialNumber();
262  std::string snright=all[k]->getSerialNumber();
263  std::string calibration_status=getCalibrationStatus(calib, all[i]);
264 
265  Fl::lock();
266  list->add("?", snleft.c_str(), snright.c_str(),
267  calibration_status.c_str(), "ok", all[i], all[k], calib);
268  Fl::unlock();
269 
270  if (calibration_status != "ok")
271  {
272  if (calibration_status == "no access" || calibration_status == "no nodemap")
273  {
274  noaccess=true;
275  }
276  else
277  {
278  misconfigured=true;
279  }
280  }
281  else
282  {
283  wrong_name=true;
284  }
285 
286  // remove devices from list
287 
288  all[i].reset();
289  all[k].reset();
290  }
291  }
292  }
293  }
294  }
295 
296  // remove shared pointers of removed devices
297 
298  {
299  size_t i=0;
300  while (i < all.size())
301  {
302  if (all[i])
303  {
304  i++;
305  }
306  else
307  {
308  all.erase(all.begin()+i);
309  }
310  }
311  }
312 
313  // print suggestions
314 
315  if (misconfigured)
316  {
317  std::ostringstream out;
318 
319  out << "Misconfigured " RC_VISCORE_NAME ". Request factory backup file from Roboception\n";
320  out << "and choose 'Reset from file ...' in menu.\n\n";
321 
322  Fl::lock();
323  buffer->text(out.str().c_str());
324  Fl::unlock();
325  }
326 
327  if (wrong_name)
328  {
329  Fl::lock();
330  buffer->text("Select " RC_VISCORE_NAME " with name '?' and press 'Reset Name'\n\n");
331  Fl::unlock();
332  }
333 
334  if (noaccess)
335  {
336  std::ostringstream out;
337 
338  out << "Cannot access cameras. Please ensure that they are not used by any\n";
339  out << "other application.\n\n";
340 
341  Fl::lock();
342  buffer->text(out.str().c_str());
343  Fl::unlock();
344  }
345 
346  if (all.size() > 0)
347  {
348  std::ostringstream out;
349 
350  if (all.size() == 1)
351  {
352  out << "The following camera may belong to an " RC_VISCORE_NAME ", but only one\n";
353  out << "is visible. Check network connection and configuration (see\n";
354  out << "troubleshooting section of the manual).\n\n";
355  }
356  else
357  {
358  out << "The following cameras may belong to an " RC_VISCORE_NAME ". Check on the label of\n";
359  out << "the " RC_VISCORE_NAME " if both serial numbers are listed below. If not, check\n";
360  out << "network connection and configuration (see troubleshooting section of the\n";
361  out << "manual). If the serial numbers of both cameras are listed, request a\n";
362  out << "backup file from Roboception and choose 'Reset from file ...' in menu.\n";
363  out << "\n\n";
364  }
365 
366  for (size_t i=0; i<all.size(); i++)
367  {
368  out << all[i]->getSerialNumber() << "\n";
369  }
370 
371  Fl::lock();
372  buffer->text(out.str().c_str());
373  Fl::unlock();
374  }
375 
376  if (!misconfigured && !noaccess && !wrong_name && all.size() == 0)
377  {
378  if (devices.size() > 0)
379  {
380  Fl::lock();
381  buffer->text("All discovered " RC_VISCORE_NAME " are ok.\n");
382  Fl::unlock();
383  }
384  else
385  {
386  std::ostringstream out;
387  out << "No " RC_VISCORE_NAME " connected.\n\n";
388  out << "Check connection and network settings of cameras with other tools.\n";
389 
390  Fl::lock();
391  buffer->text(out.str().c_str());
392  Fl::unlock();
393  }
394  }
395  }
396 
397  // close all interfaces
398 
399  for (size_t i=0; i<ilist.size(); i++)
400  {
401  ilist[i]->close();
402  }
403  }
404  catch (...)
405  {
406  Fl::lock();
407  fl_alert("Unknown exception in discover function!");
408  Fl::unlock();
409  }
410 
411  // send thread done event
412 
413  running=false;
414 }
415 
416 void resetNameWorker(rcg::Device *ldev, rcg::Device *rdev, std::atomic_bool &running)
417 {
418  try
419  {
420  try
421  {
422  // connect to device and get nodemap
423 
424  ldev->open(rcg::Device::CONTROL);
425  rdev->open(rcg::Device::CONTROL);
426 
427  resetNames(ldev->getRemoteNodeMap(), rdev->getRemoteNodeMap());
428  }
429  catch (const std::exception &ex)
430  {
431  Fl::lock();
432  fl_alert("%s", ex.what());
433  Fl::unlock();
434  }
435 
436  // close devices
437 
438  if (ldev) ldev->close();
439  if (rdev) rdev->close();
440  }
441  catch (...)
442  {
443  Fl::lock();
444  fl_alert("Unknown exception in reset name function!");
445  Fl::unlock();
446  }
447 
448  // send thread done event
449 
450  running=false;
451 }
452 
453 void storeBackupWorker(const char *backup_file, rcg::Device *ldev, rcg::Device *rdev,
454  std::atomic_bool &running)
455 {
456  try
457  {
458  try
459  {
460  // connect to device and get nodemap
461 
462  ldev->open(rcg::Device::CONTROL);
463  rdev->open(rcg::Device::CONTROL);
464 
465  std::shared_ptr<GenApi::CNodeMapRef> lmap=ldev->getRemoteNodeMap();
466  std::shared_ptr<GenApi::CNodeMapRef> rmap=rdev->getRemoteNodeMap();
467 
468  // get calibration and license file
469 
470  std::string calib=rcg::loadFile(lmap, getUserFileName(lmap).c_str(), true);
471  std::string license=rcg::loadFile(rmap, getUserFileName(rmap).c_str(), true);
472 
473  // store backup file
474 
475  std::ofstream out;
476  out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
477 
478  out.open(backup_file);
479 
480  out << calib;
481 
482  if (calib.size() > 0 && calib[calib.size()-1] != '\n')
483  {
484  out << "\n";
485  }
486 
487  out << "====================\n";
488  out << license;
489 
490  out.close();
491 
492  // show message to check calibration
493 
494  Fl::lock();
495  fl_message("Backup of " RC_VISCORE_NAME " successfully stored!");
496  Fl::unlock();
497  }
498  catch (const std::exception &ex)
499  {
500  Fl::lock();
501  fl_alert("Error '%s'", ex.what());
502  Fl::unlock();
503  }
504 
505  // close devices
506 
507  if (ldev) ldev->close();
508  if (rdev) rdev->close();
509  }
510  catch (...)
511  {
512  Fl::lock();
513  fl_alert("Unknown exception in update worker!");
514  Fl::unlock();
515  }
516 
517  running=false;
518 }
519 
520 void resetFromFileWorker(const std::vector<std::shared_ptr<rcg::Interface> > &ilist,
521  const char *backup_file, std::atomic_bool &running)
522 {
523  try
524  {
525  // load file and split into calibration and license
526 
527  std::string all;
528 
529  try
530  {
531  std::ifstream in;
532  in.exceptions(std::ifstream::failbit | std::ifstream::badbit);
533 
534  in.open(backup_file);
535  std::ostringstream out;
536  out << in.rdbuf();
537  all=out.str();
538  }
539  catch (const std::exception &ex)
540  {
541  Fl::lock();
542  fl_alert("Cannot open file '%s'", backup_file);
543  Fl::unlock();
544 
545  // send thread done event
546 
547  running=false;
548  return;
549  }
550 
551  int i1=0, i2=0;
552 
553  for (size_t i=0; i<all.size(); i++)
554  {
555  if (i1 >= 0)
556  {
557  if (all[i] == '\n')
558  {
559  i2=i;
560  break;
561  }
562  else if (all[i] != '=')
563  {
564  i1=-1;
565  }
566  }
567  else if (all[i] == '\n' && i < all.size() && all[i+1] == '=')
568  {
569  i1=i;
570  }
571  }
572 
573  if (i2 == 0)
574  {
575  Fl::lock();
576  fl_alert("Invalid " RC_VISCORE_NAME " backup file '%s'", backup_file);
577  Fl::unlock();
578 
579  // send thread done event
580 
581  running=false;
582  return;
583  }
584 
585  std::string calib=all.substr(0, i1);
586  std::string license=all.substr(i2+1);
587 
588  // validate license and get SN of left and right camera
589 
590  std::string snleft;
591  std::string snright;
592 
593  try
594  {
595  rcl::Verify verify(license);
596  std::string licdata=verify.verify();
597 
598  std::istringstream in(licdata);
599  std::string line;
600 
601  while (!in.eof())
602  {
603  std::getline(in, line);
604 
605  if (line.compare(0, 6, "extra=") == 0 && line.size() > 16)
606  {
607  if (line.compare(line.size()-10, 10, ",type=left") == 0)
608  {
609  snleft=line.substr(6, line.size()-6-10);
610  }
611  else if (line.compare(line.size()-11, 11, ",type=right") == 0)
612  {
613  snright=line.substr(6, line.size()-6-11);
614  }
615  }
616  }
617  }
618  catch (const std::exception &ex)
619  {
620  Fl::lock();
621  fl_alert("Invalid " RC_VISCORE_NAME " backup file '%s': %s", backup_file, ex.what());
622  Fl::unlock();
623 
624  // send thread done event
625 
626  running=false;
627  return;
628  }
629 
630  // find devices
631 
632  std::shared_ptr<rcg::Device> ldev;
633  std::shared_ptr<rcg::Device> rdev;
634 
635  try
636  {
637  for (size_t i=0; i<ilist.size(); i++)
638  {
639  if (!ldev) ldev=ilist[i]->getDevice(snleft.c_str());
640  if (!rdev) rdev=ilist[i]->getDevice(snright.c_str());
641  }
642 
643  if (ldev && rdev)
644  {
645  // connect to device and get nodemap
646 
647  ldev->open(rcg::Device::CONTROL);
648  rdev->open(rcg::Device::CONTROL);
649 
650  std::shared_ptr<GenApi::CNodeMapRef> lmap=ldev->getRemoteNodeMap();
651  std::shared_ptr<GenApi::CNodeMapRef> rmap=rdev->getRemoteNodeMap();
652 
653  // set names of both cameras
654 
655  resetNames(lmap, rmap);
656 
657  // store calibration file
658 
659  rcg::saveFile(lmap, getUserFileName(lmap).c_str(), calib, true);
660 
661  // store license file
662 
663  rcg::saveFile(rmap, getUserFileName(rmap).c_str(), license, true);
664 
665  // show message to check calibration
666 
667  Fl::lock();
668  fl_message(RC_VISCORE_NAME " successfully reset to factory defaults. You must check calibration before working with this camera!");
669  Fl::unlock();
670  }
671  else
672  {
673  Fl::lock();
674  fl_alert("Cannot find devices '%s' and '%s'", snleft.c_str(), snright.c_str());
675  Fl::unlock();
676  }
677  }
678  catch (const std::exception &ex)
679  {
680  Fl::lock();
681  fl_alert("Error '%s'", ex.what());
682  Fl::unlock();
683  }
684 
685  // close devices
686 
687  if (ldev) ldev->close();
688  if (rdev) rdev->close();
689  }
690  catch (...)
691  {
692  Fl::lock();
693  fl_alert("Unknown exception in update worker!");
694  Fl::unlock();
695  }
696 
697  // send thread done event
698 
699  running=false;
700 }
701 
702 void setCalibrationWorker(rcg::Device *ldev, const gutil::Properties *calib,
703  std::atomic_bool &running)
704 {
705  try
706  {
707  try
708  {
709  // connect to device and get nodemap
710 
711  ldev->open(rcg::Device::CONTROL);
712 
713  std::shared_ptr<GenApi::CNodeMapRef> lmap=ldev->getRemoteNodeMap();
714 
715  // convert calibration properties to string
716 
717  std::ostringstream calibdata;
718  calib->save(calibdata);
719 
720  // get calibration and license file
721 
722  rcg::saveFile(lmap, getUserFileName(lmap).c_str(), calibdata.str(), true);
723 
724  // show message to check calibration
725 
726  Fl::lock();
727  fl_message("Data stored successfully.");
728  Fl::unlock();
729  }
730  catch (const std::exception &ex)
731  {
732  Fl::lock();
733  fl_alert("Error '%s'", ex.what());
734  Fl::unlock();
735  }
736 
737  // close devices
738 
739  if (ldev) ldev->close();
740  }
741  catch (...)
742  {
743  Fl::lock();
744  fl_alert("Unknown exception in set calibration worker!");
745  Fl::unlock();
746  }
747 
748  running=false;
749 }
resetNameWorker
void resetNameWorker(rcg::Device *ldev, rcg::Device *rdev, std::atomic_bool &running)
Reset name of left and right camera to default.
Definition: worker.cc:416
storeBackupWorker
void storeBackupWorker(const char *backup_file, rcg::Device *ldev, rcg::Device *rdev, std::atomic_bool &running)
Store backup file.
Definition: worker.cc:453
discoverWorker
void discoverWorker(const std::vector< std::shared_ptr< rcg::Interface > > &ilist, DeviceList *list, Fl_Text_Buffer *buffer, std::atomic_bool &running)
Discover suitable devices and add them to the given list.
Definition: worker.cc:46
worker.h
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
DeviceList
Definition: device_list.h:22
resetFromFileWorker
void resetFromFileWorker(const std::vector< std::shared_ptr< rcg::Interface > > &ilist, const char *backup_file, std::atomic_bool &running)
Resetting a device from backup file.
Definition: worker.cc:520
setCalibrationWorker
void setCalibrationWorker(rcg::Device *ldev, const gutil::Properties *calib, std::atomic_bool &running)
Stroing calibration data on the left camera.
Definition: worker.cc:702


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