ValueArrayAdapter.h
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // (c) 2020 by SICK AG
3 // Project: GenApi
4 // Author: Mattias Johannesson
5 // $Header$
6 //
7 // License: This file is published under the license of the EMVA GenICam Standard Group.
8 // A text file describing the legal terms is included in your installation as 'GenICam_license.pdf'.
9 // If for some reason you are missing this file please contact the EMVA or visit the website
10 // (http://www.genicam.org) for a full copy.
11 //
12 // THIS SOFTWARE IS PROVIDED BY THE EMVA GENICAM STANDARD GROUP "AS IS"
13 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE EMVA GENICAM STANDARD GROUP
16 // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
17 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
19 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22 // POSSIBILITY OF SUCH DAMAGE.
23 //-----------------------------------------------------------------------------
29 #ifndef VALUE_ARRAY_ADAPTER_H
30 #define VALUE_ARRAY_ADAPTER_H
31 
32 #include <Base/GCException.h>
33 #include <GenApi/GenApi.h>
34 #include <GenApi/Synch.h>
35 
36 #include <algorithm>
37 #include <exception>
38 #include <functional>
39 #include <string>
40 #include <vector>
41 #include <iterator>
42 
43 /* Unified access to byte-swapping tools, possibly candidate to get
44  * extracted/extended to a reusable header. */
45 #ifdef _MSC_VER
46  #include <cstdlib>
47  #define SW16(s) _byteswap_ushort(s)
48  #define SW32(s) _byteswap_ulong(s)
49  #define SW64(s) _byteswap_uint64(s)
50 #elif __APPLE__
51  #include <libkern/OSByteOrder.h>
52  #define SW16(s) __builtin_bswap16( (s) )
53  #define SW32(s) __builtin_bswap32( (s) )
54  #define SW64(s) __builtin_bswap64( (s) )
55 #else
56  #include <byteswap.h>
57  #define SW16(s) bswap_16(s)
58  #define SW32(s) bswap_32(s)
59  #define SW64(s) bswap_64(s)
60 #endif
61 
62 namespace GENAPI_NAMESPACE
63 {
64 
65  /* Helper mini-template to allow specialized template conversions.
66  * Might be reused (or eliminated) in future, for now intended mainly to
67  * implement conversion to bool and numeric types differently.
68  * In future we might check if some type limits checking or similar is
69  * desirable. */
70  template<typename TTargetType>
72  {
73  public:
74  template<typename TSourceType>
75  static TTargetType Convert (TSourceType src)
76  {
77  return static_cast<TTargetType>(src);
78  }
79  };
80 
81  template<>
82  class TypeConverter<bool>
83  {
84  public:
85  template<typename TSourceType>
86  static bool Convert (TSourceType src)
87  {
88  return 0 != src;
89  }
90  };
91 
92  /* Helper mini-template to extract byte-swapped values for all numeric
93  * types (incl. floats).
94  * Reverse-copy by default, attempt to perform dedicated swaps for
95  * known sizes. */
96  template<size_t TValueSize>
98  {
99  public:
100  static void Extract (const void *src, void *dst)
101  {
102  std::reverse_copy(reinterpret_cast<const uint8_t*>(src),
103  reinterpret_cast<const uint8_t*>(src) + TValueSize,
104  reinterpret_cast<uint8_t*>(dst));
105  }
106  };
107  template<>
108  class SwapExtractor<8>
109  {
110  public:
111  static void Extract (const void *src, void *dst)
112  {
113  *reinterpret_cast<uint64_t*>(dst) = SW64(*reinterpret_cast<const uint64_t*>(src));
114  }
115  };
116  template<>
117  class SwapExtractor<4>
118  {
119  public:
120  static void Extract (const void *src, void *dst)
121  {
122  *reinterpret_cast<uint32_t*>(dst) = SW32(*reinterpret_cast<const uint32_t*>(src));
123  }
124  };
125  template<>
126  class SwapExtractor<2>
127  {
128  public:
129  static void Extract (const void *src, void *dst)
130  {
131  *reinterpret_cast<uint16_t*>(dst) = SW16(*reinterpret_cast<const uint16_t*>(src));
132  }
133  };
134  template<>
135  class SwapExtractor<1>
136  {
137  public:
138  static void Extract (const void *src, void *dst)
139  {
140  *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src);
141  }
142  };
143 
153  {
154  protected:
155  CValueArrayAdapterBase(IValue* base_value, IInteger *selector);
156  virtual ~CValueArrayAdapterBase ();
157  private:
158  /* Not copyable */
161 
162  protected:
163  /* Retrieves current status of the value array parameters and reads
164  * "shadow copy" of the memory holding the array from the port.
165  * It is caller's responsibility to apply the lock as needed.
166  * Note: the lock is recursive and ReadFromPort() uses only read operations,
167  * no write that would trigger callbacks, it is therefore safe to apply
168  * the lock from outside. */
169  void ReadFromPort ();
170  CLock& GetLock() const;
171 
172  protected:
173  /* Flag indicating successful parse of the dependencies and initialization
174  * of the adapter - if false, the adapter cannot be used. */
175  bool is_valid;
176  /* Static information sniffed from the XML/nodemap at time of creation
177  * of the adapter - info about the structure that does not change at runtime.
178  * These are guaranteed to be up-to-date once the instance is constructed. */
181  bool is_signed;
183  uint32_t lsbit;
184  uint32_t msbit;
185  uint64_t lsbit_mask;
186  /* Dynamic values used for every single read. In particular read copy
187  * of the register itself.
188  * These are updated during each call to ReadFromPort() that should happen
189  * just before attempt to extract the actual values. */
195 
196  private:
197  /* Implementation details */
198  struct ValueArrayInternals;
199  ValueArrayInternals* pinternal;
200  };
201 
216  template<typename TValueNodeType, typename TOutputValueType, typename TEffectiveValueType = TOutputValueType>
218  {
219  public:
227  CValueArrayAdapter(TValueNodeType* base_value, IInteger *selector)
228  : CValueArrayAdapterBase (base_value, selector),
229  current_array_getter(NULL)
230  { }
231 
240  bool IsValid() const
241  {
242  return is_valid;
243  }
244 
267  std::vector<TOutputValueType> GetAllValues()
268  {
269  std::vector<TOutputValueType> values(current_num_values);
270  GetAllValues (values);
271  return values;
272  }
273 
301  void GetAllValues(std::vector<TOutputValueType> &values)
302  {
303  if (!is_valid)
304  {
305  throw RUNTIME_EXCEPTION("Invalid value array adapter");
306  }
307 
308  /* Lock the entire operation, protecting not only against concurrent
309  * changes of underlying nodemap parameters, but also against concurrent
310  * accessess to the value array adapter itself. */
311  AutoLock l(GetLock());
312 
313  /* Freeze current state of all the dynamic properties and read the register. */
314  PrepareValues ();
315 
316  assert (current_array_getter != NULL);
317  (this->*current_array_getter) (values);
318  }
319 
333  static bool CheckAdvertisedCompatibility(TValueNodeType* base_value, IInteger *selector)
334  {
335  try
336  {
337  if (!base_value || !selector)
338  {
339  return false;
340  }
341 
342  /* The nodes must necessarily belong to the same nodemap */
343  INodeMap *node_map = base_value->GetNode()->GetNodeMap();
344  if (node_map != selector->GetNode()->GetNodeMap())
345  {
346  return false;
347  }
348 
349  /* The set of candidates is per SFNC advertised through string feature
350  * ValueArrayCandidates. */
351  CStringPtr candidates_node = node_map->GetNode("ValueArrayCandidates");
352  if (!candidates_node.IsValid() || !IsReadable(candidates_node))
353  {
354  return false;
355  }
356  GENICAM_NAMESPACE::gcstring rawstr = candidates_node->GetValue ();
357 
358  /* Erase everything starting from a first occurence of the '#' character.
359  * This is a backdoor to allow extending the ValueArrayCandidates format
360  * in a backward compatible way. */
361  GENICAM_NAMESPACE::gcstring candidates_str = rawstr.substr (0, rawstr.find_first_of("#"));
362 
363  /* The list of adapter candidates is encoded (per SFNC) as comma
364  * separated list of Value[Selector] entries. */
365  GENICAM_NAMESPACE::gcstring_vector tokens;
366  Tokenize(candidates_str, tokens, ",");
367 
368  /* Finally check if the requested value/selector pair is in the list. */
369  GENICAM_NAMESPACE::gcstring wanted = base_value->GetNode()->GetName()
370  + "[" + selector->GetNode()->GetName() + "]";
371  return tokens.contains (wanted);
372  }
373  catch (const GenICam::GenericException &)
374  {
375  return false;
376  }
377  }
378 
379  private:
380  /* Array getter implementations for individual field types.
381  * Implemented as complete array getter rather than just single value getter
382  * called from a loop to allow for unrolling-related compiler optimizations. */
383  template<typename TFieldType>
384  void GetArrayOfFieldValues (std::vector<TOutputValueType> &values)
385  {
386  assert (current_reg_length!=0 && current_address_step != 0);
387 
388  /* Resize the output (note that vector capacity does not change if
389  * the original is bigger than needed). */
390  values.resize (current_num_values);
391 
392  /* Extract the values.
393  * The memory read into our shadow copy starts at first desired value
394  * (see PrepareValues), therefore we start at offset 0. */
395  if (swap_endian)
396  {
397  ExtractFieldValues_Swap<TFieldType> (current_num_values,
398  static_cast<size_t>(current_address_step),
399  current_array_shadow, &values[0]);
400  }
401  else
402  {
403  ExtractFieldValues_Noswap<TFieldType> (current_num_values,
404  static_cast<size_t>(current_address_step),
405  current_array_shadow, &values[0]);
406  }
407  }
408  template<typename TFieldType>
409  void GetArrayOfFieldBits (std::vector<TOutputValueType> &values)
410  {
411  assert (current_reg_length!=0 && current_address_step != 0);
412 
413  /* Resize the output (note that vector capacity does not change if
414  * the original is bigger than needed). */
415  values.resize (current_num_values);
416 
417  /* Extract the values.
418  * The memory read into our shadow copy starts at first desired value
419  * (see PrepareValues), therefore we start at offset 0. */
420  if (swap_endian)
421  {
422  ExtractFieldBits_Swap<TFieldType> (current_num_values,
423  static_cast<size_t>(current_address_step),
424  lsbit_mask, lsbit,
425  current_array_shadow, &values[0]);
426  }
427  else
428  {
429  ExtractFieldBits_Noswap<TFieldType> (current_num_values,
430  static_cast<size_t>(current_address_step),
431  lsbit_mask, lsbit,
432  current_array_shadow, &values[0]);
433  }
434  }
435  /* Static workers responsible for the main-loop part of the GetArray-functions.
436  * Separating similar workers with code duplication and using all params as
437  * local variables instead of referring to member variables to assist
438  * optimizer as much as possible. */
439  template<typename TFieldType>
440  static void ExtractFieldValues_Noswap(size_t num_values, size_t address_step,
441  const uint8_t *src, TOutputValueType *dst)
442  {
443  for (size_t i = 0; i < num_values; ++i)
444  {
445  const uint8_t *field_ptr = src + i * address_step;
446 
447  TFieldType field_value = *reinterpret_cast<const TFieldType*>(field_ptr);
448  dst[i] = static_cast<TOutputValueType>(EffectiveValue (field_value));
449  }
450  }
451  template<typename TFieldType>
452  static void ExtractFieldValues_Swap(size_t num_values, size_t address_step,
453  const uint8_t *src, TOutputValueType *dst)
454  {
455  for (size_t i = 0; i < num_values; ++i)
456  {
457  const uint8_t *field_ptr = src + i * address_step;
458 
459  TFieldType field_value = ReadSwapped<TFieldType> (field_ptr);
460  dst[i] = static_cast<TOutputValueType>(EffectiveValue (field_value));
461  }
462  }
463  template<typename TFieldType>
464  static void ExtractFieldBits_Noswap(size_t num_values, size_t address_step,
465  uint64_t mask, size_t shift,
466  const uint8_t *src, TOutputValueType *dst)
467  {
468  for (size_t i = 0; i < num_values; ++i)
469  {
470  const uint8_t *field_ptr = src + i * address_step;
471 
472  TFieldType field_value = *reinterpret_cast<const TFieldType*>(field_ptr);
473  uint64_t field_bits = mask & (field_value >> shift);
474  dst[i] = static_cast<TOutputValueType>(EffectiveValue (field_bits));
475  }
476  }
477  template<typename TFieldType>
478  static void ExtractFieldBits_Swap(size_t num_values, size_t address_step,
479  uint64_t mask, size_t shift,
480  const uint8_t *src, TOutputValueType *dst)
481  {
482  for (size_t i = 0; i < num_values; ++i)
483  {
484  const uint8_t *field_ptr = src + i * address_step;
485 
486  TFieldType field_value = ReadSwapped<TFieldType> (field_ptr);
487  uint64_t field_bits = mask & (field_value >> shift);
488  dst[i] = static_cast<TOutputValueType>(EffectiveValue (field_bits));
489  }
490  }
491 
492  /* Common worker for the public read-functions.
493  * Prepares for effective value-by-value read - computes current values
494  * of the possibly dynamic parameters, reads from the register into
495  * the shadow copy. */
497  {
498  /* Scan the current dependencies and read the underlying memory of the
499  * value array from the port. Ready for extraction.
500  * This updates all the array "coordinates" (address/step/etc.) and
501  * gets the memory blob from which it can be extracted. */
502  ReadFromPort ();
503 
504  /* Finally, knowing all parameters about the array, we can construct
505  * the value getter function. */
506  if (is_int_reg)
507  {
508  /* Integer register */
509  if (masked_int)
510  {
511  /* Masked integer value.
512  * Supported only with unsigned MaskedIntReg registers, signed refused during consruction. */
513  if (is_signed)
514  {
515  assert (false && "Signed MaskeIntReg should be refused in constructor");
516  throw RUNTIME_EXCEPTION("Unsupported signed masked integer register");
517  }
518 
519  /* Unsigned integer */
520  switch (current_reg_length)
521  {
522  case 8:
523  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldBits<uint64_t>;
524  break;
525 
526  case 4:
527  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldBits<uint32_t>;
528  break;
529 
530  case 2:
531  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldBits<uint16_t>;
532  break;
533 
534  case 1:
535  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldBits<uint8_t>;
536  break;
537 
538  default:
539  throw RUNTIME_EXCEPTION("Unsupported unsigned integer register length");
540  }
541  } /* if (masked_int) */
542  else
543  {
544  /* Full (not masked) integer value */
545  if (is_signed)
546  {
547  /* Signed integer */
548  switch (current_reg_length)
549  {
550  case 8:
551  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<int64_t>;
552  break;
553 
554  case 4:
555  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<int32_t>;
556  break;
557 
558  case 2:
559  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<int16_t>;
560  break;
561 
562  case 1:
563  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<int8_t>;
564  break;
565 
566  default:
567  throw RUNTIME_EXCEPTION("Unsupported signed integer register length");
568  }
569  } /* if (signed) */
570  else
571  {
572  /* Unsigned integer */
573  switch (current_reg_length)
574  {
575  case 8:
576  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<uint64_t>;
577  break;
578 
579  case 4:
580  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<uint32_t>;
581  break;
582 
583  case 2:
584  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<uint16_t>;
585  break;
586 
587  case 1:
588  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<uint8_t>;
589  break;
590 
591  default:
592  throw RUNTIME_EXCEPTION("Unsupported unsigned integer register length");
593  }
594  } /* if-else (signed) */
595  } /* if-else (masked_int) */
596  } /* if (is_int_reg) */
597  else
598  {
599  /* Float register. */
600  switch (current_reg_length)
601  {
602  case 8:
603  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<float64_t>;
604  break;
605 
606  case 4:
607  current_array_getter = &CValueArrayAdapter::GetArrayOfFieldValues<float32_t>;
608  break;
609 
610  default:
611  throw RUNTIME_EXCEPTION("Unsupported float register length");
612  }
613  } /* if-else (is_int_reg) */
614  }
615 
616  template<typename TRawType>
617  static TEffectiveValueType EffectiveValue (TRawType raw_value)
618  {
620  }
621 
622  template<typename TFieldType>
623  static TFieldType ReadSwapped (const void *ptr)
624  {
625  TFieldType result;
627  return result;
628  }
629 
630  private:
631  typedef void (CValueArrayAdapter::*ArrayGetterFunction)(std::vector<TOutputValueType> &values);
632  ArrayGetterFunction current_array_getter;
633  };
634 
635 
641  class CIntegerValueArray : public CValueArrayAdapter<IInteger, int64_t>
642  {
643  public:
644  CIntegerValueArray(IInteger *base_value, IInteger *selector)
645  : CValueArrayAdapter<IInteger, int64_t> (base_value, selector)
646  {
647  }
648  };
649 
655  class CFloatValueArray : public CValueArrayAdapter<IFloat, double>
656  {
657  public:
658  CFloatValueArray(IFloat *base_value, IInteger *selector)
659  : CValueArrayAdapter<IFloat, double> (base_value, selector)
660  {
661  }
662  };
663 
670  class CBooleanValueArray : public CValueArrayAdapter<IBoolean, uint8_t, bool>
671  {
672  public:
673  CBooleanValueArray(IBoolean *base_value, IInteger *selector)
674  : CValueArrayAdapter<IBoolean, uint8_t, bool> (base_value, selector)
675  {
676  }
677  };
678 
679 }
680 
681 #endif // VALUE_ARRAY_ADAPTER_H
682 
GENICAM_INTERFACE GENAPI_DECL_ABSTRACT IBoolean
Interface for Boolean properties.
Definition: IBoolean.h:61
void GetArrayOfFieldValues(std::vector< TOutputValueType > &values)
static void Extract(const void *src, void *dst)
static bool CheckAdvertisedCompatibility(TValueNodeType *base_value, IInteger *selector)
Check value/selector feature pair suitability for use with the adapter.
GENICAM_INTERFACE IInteger
Interface for integer properties.
Definition: IFloat.h:114
#define SW64(s)
static bool Convert(TSourceType src)
void GetArrayOfFieldBits(std::vector< TOutputValueType > &values)
bool IsValid() const
Check if the instance is valid and useable.
static TEffectiveValueType EffectiveValue(TRawType raw_value)
CFloatValueArray(IFloat *base_value, IInteger *selector)
virtual size_t find_first_of(const gcstring &str, size_t offset=0) const
CIntegerValueArray(IInteger *base_value, IInteger *selector)
Concrete value array implementation to be used with IInteger based target value nodes.
virtual void operator=(bool Value)
Set node value.
Definition: IBoolean.h:64
static void Extract(const void *src, void *dst)
__int64 int64_t
Definition: config-win32.h:21
bool IsReadable(EAccessMode AccessMode)
Tests if readable.
Definition: INode.h:178
virtual gcstring substr(size_t offset=0, size_t count=GCSTRING_NPOS) const
GENICAM_INTERFACE INodeMap
Interface to access the node map.
Definition: INode.h:52
#define GENAPI_DECL
Definition: GenApiDll.h:55
static void Extract(const void *src, void *dst)
CBooleanValueArray(IBoolean *base_value, IInteger *selector)
#define RUNTIME_EXCEPTION
Fires a runtime exception, e.g. throw RUNTIME_EXCEPTION("buh!")
Definition: GCException.h:247
GCBASE_API void Tokenize(const gcstring &str, gcstring_vector &tokens, const gcstring &delimiters=" ")
splits str input string into a list of tokens using the delimiter
void GetAllValues(std::vector< TOutputValueType > &values)
Get all values of the array.
#define SW32(s)
Base class wrapping internal implementation details of the value array adapter functionality.
static void Extract(const void *src, void *dst)
#define SW16(s)
Encapsulates a GenApi pointer dealing with the dynamic_cast automatically.
Definition: Pointer.h:51
Main include file for using GenApi with smart pointers.
Adapter for accessing structured register known to include an array of selector-iterated values...
static TTargetType Convert(TSourceType src)
std::vector< TOutputValueType > GetAllValues()
Get all values of the array.
static void ExtractFieldBits_Swap(size_t num_values, size_t address_step, uint64_t mask, size_t shift, const uint8_t *src, TOutputValueType *dst)
Concrete value array implementation to be used with IFloat based target value nodes.
static TFieldType ReadSwapped(const void *ptr)
CValueArrayAdapter(TValueNodeType *base_value, IInteger *selector)
Creates a CValueArrayAdapter object.
static void ExtractFieldValues_Noswap(size_t num_values, size_t address_step, const uint8_t *src, TOutputValueType *dst)
A string class which is a clone of std::string.
Definition: GCString.h:52
Concrete value array implementation to be used with IBoolean based target value nodes.
bool IsValid() const
true if the pointer is valid
Definition: Pointer.h:110
GENICAM_INTERFACE GENAPI_DECL_ABSTRACT IFloat
Interface for float properties.
Definition: IFloat.h:60
GenICam&#39;s exception class.
Definition: GCException.h:63
Definition of Lock classes.
static void ExtractFieldBits_Noswap(size_t num_values, size_t address_step, uint64_t mask, size_t shift, const uint8_t *src, TOutputValueType *dst)
static void Extract(const void *src, void *dst)
GENICAM_INTERFACE GENAPI_DECL_ABSTRACT IValue
Interface for value properties.
Definition: IValue.h:61
Lexical analyzer for CIntSwissKnife.
Definition: Autovector.h:48
A lock class.
Definition: Synch.h:63
static void ExtractFieldValues_Swap(size_t num_values, size_t address_step, const uint8_t *src, TOutputValueType *dst)
virtual CLock & GetLock() const =0
Returns the lock which guards the node map.


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Wed Mar 17 2021 02:48:41