system.cc
Go to the documentation of this file.
1 /*
2  * This file is part of the rc_genicam_api package.
3  *
4  * Copyright (c) 2017 Roboception GmbH
5  * All rights reserved
6  *
7  * Author: Heiko Hirschmueller
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include "system.h"
37 
38 #include "gentl_wrapper.h"
39 #include "exception.h"
40 #include "interface.h"
41 #include "cport.h"
42 
43 #include <iostream>
44 
45 #ifdef _WIN32
46 #include <Windows.h>
47 #include <cstring>
48 #undef min
49 #undef max
50 #endif
51 
52 namespace rcg
53 {
54 
56 {
57  if (n_open > 0 && tl != 0)
58  {
59  gentl->TLClose(tl);
60  }
61 
62  gentl->GCCloseLib();
63 }
64 
65 namespace
66 {
67 
68 std::recursive_mutex system_mtx;
69 std::vector<std::shared_ptr<System> > system_list;
70 std::string system_path;
71 std::string system_ignore;
72 
73 int find(const std::vector<std::shared_ptr<System> > &list, const std::string &filename)
74 {
75  for (size_t i=0; i<list.size(); i++)
76  {
77  if (list[i]->getFilename() == filename)
78  {
79  return static_cast<int>(i);
80  }
81  }
82 
83  return -1;
84 }
85 
86 #ifdef _WIN32
87 static std::string getPathToThisDll()
88 {
89  HMODULE hm = nullptr;
90  if (GetModuleHandleExA(
91  GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
92  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
93  reinterpret_cast<LPCSTR>(&getPathToThisDll), &hm) == 0)
94  {
95  return {};
96  }
97 
98  char path[MAX_PATH];
99  if (GetModuleFileNameA(hm, path, sizeof(path)) == 0)
100  {
101  return {};
102  }
103 
104  std::string p{ path };
105  const auto bs_pos = p.rfind('\\');
106  if (bs_pos != std::string::npos)
107  {
108  p = p.substr(0, bs_pos);
109  }
110 
111  return p;
112 }
113 
114 #endif
115 
116 }
117 
118 bool System::setSystemsPath(const char *path, const char *ignore)
119 {
120  std::lock_guard<std::recursive_mutex> lock(system_mtx);
121 
122  if (system_list.size() == 0)
123  {
124  system_path="";
125  system_ignore="";
126 
127  if (path == 0 || path[0] == '\0')
128  {
129 #ifdef _WIN32
130  // under Windows, use the path to the current executable as fallback
131 
132  const size_t n=256;
133  char procpath[n];
134  std::string path_to_exe;
135  if (GetModuleFileNameA(NULL, procpath, n-1) > 0)
136  {
137  procpath[n-1]='\0';
138 
139  char *p=strrchr(procpath, '\\');
140  if (p != 0) *p='\0';
141 
142  path_to_exe=procpath;
143 
144  if (system_path.size() > 0) system_path+=";";
145 
146  system_path += path_to_exe;
147  }
148 
149  // another fallback is the path to the current library
150 
151  const auto path_to_this_dll = getPathToThisDll();
152  if (!path_to_this_dll.empty() && path_to_this_dll != path_to_exe)
153  {
154  if (system_path.size() > 0) system_path+=";";
155 
156  system_path += path_to_this_dll;
157  }
158 
159  // and possible sub-directories of the library
160 
161  HANDLE file_handle;
162  WIN32_FIND_DATAA file_info;
163 
164  file_handle=FindFirstFileA((path_to_this_dll+"\\*").c_str(), &file_info);
165 
166  if (file_handle != INVALID_HANDLE_VALUE)
167  {
168  do
169  {
170  if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 && file_info.cFileName[0] != '.' )
171  {
172  system_path += ";" + path_to_this_dll + "\\" + file_info.cFileName;
173  }
174  }
175  while (FindNextFileA(file_handle, &file_info));
176 
177  FindClose(file_handle);
178  }
179 #else
180  // otherwise, use the absolute install path to the default transport layer
181 
182  system_path=GENTL_INSTALL_PATH;
183 #endif
184  }
185  else
186  {
187  system_path=path;
188  }
189 
190  if (ignore != 0)
191  {
192  system_ignore=ignore;
193  }
194 
195  return true;
196  }
197 
198  return false;
199 }
200 
201 std::vector<std::shared_ptr<System> > System::getSystems()
202 {
203  std::lock_guard<std::recursive_mutex> lock(system_mtx);
204  std::vector<std::shared_ptr<System> > ret;
205 
206  // ensure that system_path is defined
207 
208  if (system_path.size() == 0)
209  {
210  const char *env=0;
211  if (sizeof(size_t) == 8)
212  {
213  env="GENICAM_GENTL64_PATH";
214  }
215  else
216  {
217  env="GENICAM_GENTL32_PATH";
218  }
219 
220  setSystemsPath(std::getenv(env), 0);
221  }
222 
223  // get list of all available transport layer libraries
224 
225  std::vector<std::string> name=getAvailableGenTLs(system_path.c_str());
226  std::ostringstream info;
227 
228  // create list of systems according to the list, using either existing
229  // systems or instantiating new ones
230 
231  for (size_t i=0; i<name.size(); i++)
232  {
233  int k=find(system_list, name[i]);
234 
235  if (system_ignore.size() > 0)
236  {
237  // skipping if name equals ignore
238 
239  if (name[i].size() >= system_ignore.size() &&
240  name[i].substr(name[i].size()-system_ignore.size()) == system_ignore)
241  {
242  continue;
243  }
244  }
245 
246  if (k >= 0)
247  {
248  ret.push_back(system_list[static_cast<size_t>(k)]);
249  }
250  else
251  {
252  try
253  {
254  System *p=new System(name[i]);
255  ret.push_back(std::shared_ptr<System>(p));
256  }
257  catch (const std::exception &ex)
258  {
259  // ignore transport layers that cannot be used, but collect reason
260  // for failure
261 
262  info << ex.what() << std::endl;
263  }
264  }
265  }
266 
267  // remember returned list for reusing existing systems on the next call
268 
269  system_list=ret;
270 
271  // throw exception if no transport layers are available
272 
273  if (ret.size() == 0)
274  {
275  info << "No transport layers found in path: " << system_path;
276  throw GenTLException(info.str());
277  }
278 
279  return ret;
280 }
281 
283 {
284  std::lock_guard<std::recursive_mutex> lock(system_mtx);
285 
286  // clear all interfaces explicitly as part of ENUM-WORKAROUND
287  for (size_t i=0; i<system_list.size(); i++)
288  {
289  system_list[i]->clearInterfaces();
290  }
291 
292  system_list.clear();
293 }
294 
295 const std::string &System::getFilename() const
296 {
297  return filename;
298 }
299 
301 {
302  std::lock_guard<std::recursive_mutex> lock(mtx);
303 
304  if (n_open == 0)
305  {
306  if (gentl->TLOpen(&tl) != GenTL::GC_ERR_SUCCESS)
307  {
308  throw GenTLException("System::open()", gentl);
309  }
310  }
311 
312  n_open++;
313 }
314 
316 {
317  std::lock_guard<std::recursive_mutex> lock(mtx);
318 
319  if (n_open > 0)
320  {
321  n_open--;
322 
323  if (n_open == 0)
324  {
325  gentl->TLClose(tl);
326  tl=0;
327 
328  nodemap=0;
329  cport=0;
330  }
331  }
332 }
333 
334 namespace
335 {
336 
337 int find(const std::vector<std::shared_ptr<Interface> > &list, const std::string &id)
338 {
339  for (size_t i=0; i<list.size(); i++)
340  {
341  if (list[i]->getID() == id)
342  {
343  return static_cast<int>(i);
344  }
345  }
346 
347  return -1;
348 }
349 
350 }
351 
352 std::vector<std::shared_ptr<Interface> > System::getInterfaces()
353 {
354  std::lock_guard<std::recursive_mutex> lock(mtx);
355  std::vector<std::shared_ptr<Interface> > ret=ilist;
356 
357  // ENUM-WORKAROUND: Interfaces are only enumerated once and kept open as a
358  // (temporary) workaround for a bug in the Baumer GenTL layer 2.1.0 for GEV
359  // that is used by default. The bug causes memory and CPU time to
360  // increase on every call of TLUpdateInterfaceList().
361 
362  if (tl != 0 && ilist.size() == 0)
363  {
364  // get list of previously requested interfaces that are still in use
365 
366  std::vector<std::shared_ptr<Interface> > current;
367 
368 /*
369  for (size_t i=0; i<ilist.size(); i++)
370  {
371  std::shared_ptr<Interface> p=ilist[i].lock();
372  if (p)
373  {
374  current.push_back(p);
375  }
376  }
377 */
378 
379  // update available interfaces
380 
381  if (gentl->TLUpdateInterfaceList(tl, 0, 10) != GenTL::GC_ERR_SUCCESS)
382  {
383  throw GenTLException("System::getInterfaces()", gentl);
384  }
385 
386  // create list of interfaces, using either existing interfaces or
387  // instantiating new ones
388 
389  uint32_t n=0;
390  if (gentl->TLGetNumInterfaces(tl, &n) != GenTL::GC_ERR_SUCCESS)
391  {
392  throw GenTLException("System::getInterfaces()", gentl);
393  }
394 
395  for (uint32_t i=0; i<n; i++)
396  {
397  char tmp[256]="";
398  size_t size=sizeof(tmp);
399 
400  if (gentl->TLGetInterfaceID(tl, i, tmp, &size) != GenTL::GC_ERR_SUCCESS)
401  {
402  throw GenTLException("System::getInterfaces()", gentl);
403  }
404 
405  int k=find(current, tmp);
406 
407  if (k >= 0)
408  {
409  ret.push_back(current[static_cast<size_t>(k)]);
410  }
411  else
412  {
413  ret.push_back(std::shared_ptr<Interface>(new Interface(shared_from_this(), gentl, tmp)));
414  }
415  }
416 
417  // update internal list of interfaces for reusage on next call
418 
419  ilist.clear();
420  for (size_t i=0; i<ret.size(); i++)
421  {
422  ilist.push_back(ret[i]);
423  }
424 
425  // open interfaces to avoid re-enumeration as part of ENUM-WORKAROUND
426 
427  for (size_t i=0; i<ret.size(); i++)
428  {
429  ret[i]->open();
430  }
431  }
432 
433  return ret;
434 }
435 
436 namespace
437 {
438 
439 std::string cTLGetInfo(GenTL::TL_HANDLE tl, const std::shared_ptr<const GenTLWrapper> &gentl,
440  GenTL::TL_INFO_CMD info)
441 {
442  std::string ret;
443 
445  char tmp[1024]="";
446  size_t tmp_size=sizeof(tmp);
448 
449  if (tl != 0)
450  {
451  err=gentl->TLGetInfo(tl, info, &type, tmp, &tmp_size);
452  }
453  else
454  {
455  err=gentl->GCGetInfo(info, &type, tmp, &tmp_size);
456  }
457 
459  {
460  for (size_t i=0; i<tmp_size && tmp[i] != '\0'; i++)
461  {
462  ret.push_back(tmp[i]);
463  }
464  }
465 
466  return ret;
467 }
468 
469 }
470 
471 std::string System::getID()
472 {
473  std::lock_guard<std::recursive_mutex> lock(mtx);
474  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_ID);
475 }
476 
477 std::string System::getVendor()
478 {
479  std::lock_guard<std::recursive_mutex> lock(mtx);
480  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_VENDOR);
481 }
482 
483 std::string System::getModel()
484 {
485  std::lock_guard<std::recursive_mutex> lock(mtx);
486  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_MODEL);
487 }
488 
489 std::string System::getVersion()
490 {
491  std::lock_guard<std::recursive_mutex> lock(mtx);
492  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_VERSION);
493 }
494 
495 std::string System::getTLType()
496 {
497  std::lock_guard<std::recursive_mutex> lock(mtx);
498  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_TLTYPE);
499 }
500 
501 std::string System::getName()
502 {
503  std::lock_guard<std::recursive_mutex> lock(mtx);
504  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_NAME);
505 }
506 
507 std::string System::getPathname()
508 {
509  std::lock_guard<std::recursive_mutex> lock(mtx);
510  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_PATHNAME);
511 }
512 
514 {
515  std::lock_guard<std::recursive_mutex> lock(mtx);
516  return cTLGetInfo(tl, gentl, GenTL::TL_INFO_DISPLAYNAME);
517 }
518 
520 {
521  std::lock_guard<std::recursive_mutex> lock(mtx);
522  bool ret=true;
523 
525  int32_t v;
526  size_t size=sizeof(v);
528 
529  if (tl != 0)
530  {
531  err=gentl->TLGetInfo(tl, GenTL::TL_INFO_CHAR_ENCODING, &type, &v, &size);
532  }
533  else
534  {
535  err=gentl->GCGetInfo(GenTL::TL_INFO_CHAR_ENCODING, &type, &v, &size);
536  }
537 
538  if (err == GenTL::GC_ERR_SUCCESS && type == GenTL::INFO_DATATYPE_INT32 &&
540  {
541  ret=false;
542  }
543 
544  return ret;
545 }
546 
548 {
549  std::lock_guard<std::recursive_mutex> lock(mtx);
550  uint32_t ret=0;
551 
553  size_t size=sizeof(ret);
554 
555  if (tl != 0)
556  {
557  gentl->TLGetInfo(tl, GenTL::TL_INFO_GENTL_VER_MAJOR, &type, &ret, &size);
558  }
559  else
560  {
561  gentl->GCGetInfo(GenTL::TL_INFO_GENTL_VER_MAJOR, &type, &ret, &size);
562  }
563 
564  return static_cast<int>(ret);
565 }
566 
568 {
569  std::lock_guard<std::recursive_mutex> lock(mtx);
570  uint32_t ret=0;
571 
573  size_t size=sizeof(ret);
574 
575  if (tl != 0)
576  {
577  gentl->TLGetInfo(tl, GenTL::TL_INFO_GENTL_VER_MINOR, &type, &ret, &size);
578  }
579  else
580  {
581  gentl->GCGetInfo(GenTL::TL_INFO_GENTL_VER_MINOR, &type, &ret, &size);
582  }
583 
584  return static_cast<int>(ret);
585 }
586 
587 std::shared_ptr<GenApi::CNodeMapRef> System::getNodeMap()
588 {
589  std::lock_guard<std::recursive_mutex> lock(mtx);
590  if (tl != 0 && !nodemap)
591  {
592  cport=std::shared_ptr<CPort>(new CPort(gentl, &tl));
593  nodemap=allocNodeMap(gentl, tl, cport.get());
594  }
595 
596  return nodemap;
597 }
598 
599 void *System::getHandle() const
600 {
601  return tl;
602 }
603 
605 {
606  // close and clear all interfaces as part of ENUM-WORKAROUND
607  for (size_t i=0; i<ilist.size(); i++)
608  {
609  ilist[i]->close();
610  }
611 
612  ilist.clear();
613 }
614 
615 System::System(const std::string &_filename)
616 {
617  filename=_filename;
618 
619  gentl=std::shared_ptr<const GenTLWrapper>(new GenTLWrapper(filename));
620 
621  if (gentl->GCInitLib() != GenTL::GC_ERR_SUCCESS)
622  {
623  throw GenTLException("System::System()", gentl);
624  }
625 
626  n_open=0;
627  tl=0;
628 }
629 
630 }
System(const std::string &_filename)
Definition: system.cc:615
std::string getDisplayName()
Returns the display name of the GenTL provider.
Definition: system.cc:513
const std::string & getFilename() const
Get file name from which this system was created.
Definition: system.cc:295
std::shared_ptr< GenApi::CNodeMapRef > nodemap
Definition: system.h:268
This is the port definition that connects GenAPI to GenTL.
Definition: cport.h:52
void * tl
Definition: system.h:265
static std::vector< std::shared_ptr< System > > getSystems()
This function creates systems for all producers that can be found.
Definition: system.cc:201
void * TL_HANDLE
Definition: GenTL_v1_6.h:222
std::shared_ptr< CPort > cport
Definition: system.h:267
std::vector< std::shared_ptr< Interface > > getInterfaces()
Returns the currently available interfaces.
Definition: system.cc:352
void close()
Closes the system.
Definition: system.cc:315
The system class encapsulates a Genicam transport layer.
Definition: system.h:58
std::shared_ptr< const GenTLWrapper > gentl
Definition: system.h:260
static void clearSystems()
Clears the internal list of systems.
Definition: system.cc:282
int n_open
Definition: system.h:264
std::string getVendor()
Returns the vendor name of the GenTL provider.
Definition: system.cc:477
int getMinorVersion()
Returns the minor version number.
Definition: system.cc:567
void * getHandle() const
Get internal handle of open transport layer.
Definition: system.cc:599
void clearInterfaces()
Definition: system.cc:604
static bool setSystemsPath(const char *path, const char *ignore)
Set the path for finding GenTL producers on the file system and the name of a producer that should be...
Definition: system.cc:118
std::recursive_mutex mtx
Definition: system.h:262
void open()
Opens the system for working with it.
Definition: system.cc:300
std::shared_ptr< GenApi::CNodeMapRef > getNodeMap()
Returns the node map of this object.
Definition: system.cc:587
int32_t INFO_DATATYPE
Definition: GenTL_v1_6.h:261
std::string getName()
Returns the file name of the GenTL provider.
Definition: system.cc:501
std::vector< std::string > getAvailableGenTLs(const char *paths)
The function uses the given list files of paths that is separated by colons or semicolons, depending on the used operating system, and returns all files with the suffix .cti.
Wrapper for dynamically loaded GenICam transport layers.
Definition: gentl_wrapper.h:62
std::shared_ptr< GenApi::CNodeMapRef > allocNodeMap(std::shared_ptr< const GenTLWrapper > gentl, void *port, CPort *cport, const char *xml)
Convenience function that returns a GenICam node map from the given port.
Definition: cport.cc:156
int32_t GC_ERROR
Definition: GenTL_v1_6.h:185
bool isCharEncodingASCII()
Returns the character encoding.
Definition: system.cc:519
Definition: buffer.cc:47
std::string getVersion()
Returns the version of the GenTL provider.
Definition: system.cc:489
std::string getModel()
Returns the model of the GenTL provider.
Definition: system.cc:483
std::string getPathname()
Returns the full path name of the GenTL provider.
Definition: system.cc:507
std::string filename
Definition: system.h:259
std::string getTLType()
Returns the transport layer type of the GenTL provider.
Definition: system.cc:495
int32_t TL_INFO_CMD
Definition: GenTL_v1_6.h:287
int getMajorVersion()
Returns the major version number.
Definition: system.cc:547
The interface class encapsulates a Genicam interface.
Definition: interface.h:54
std::vector< std::shared_ptr< Interface > > ilist
Definition: system.h:271
std::string getID()
Returns the ID of the GenTL provider.
Definition: system.cc:471


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Sun Jun 18 2023 02:43:55