Point Cloud Library (PCL)  1.12.1-dev
grabber.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder(s) nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #pragma once
36 
37 #include <pcl/pcl_config.h>
38 
39 // needed for the grabber interface / observers
40 #include <map>
41 #include <memory>
42 #include <iostream>
43 #include <string>
44 #include <typeinfo>
45 #include <tuple>
46 #include <vector>
47 #include <sstream>
48 #include <pcl/pcl_macros.h>
49 #include <pcl/exceptions.h>
50 #include <boost/signals2.hpp> // for connection, signal, ...
51 
52 namespace pcl
53 {
54 
55  /** \brief Grabber interface for PCL 1.x device drivers
56  * \author Suat Gedikli <gedikli@willowgarage.com>
57  * \ingroup io
58  */
60  {
61  public:
62  /**
63  * \brief Default ctor
64  */
65  Grabber() = default;
66 
67  /**
68  * \brief No copy ctor since Grabber can't be copied
69  */
70  Grabber(const Grabber&) = delete;
71 
72  /**
73  * \brief No copy assign operator since Grabber can't be copied
74  */
75  Grabber& operator=(const Grabber&) = delete;
76 
77  /**
78  * \brief Move ctor
79  */
80  Grabber(Grabber&&) = default;
81 
82  /**
83  * \brief Move assign operator
84  */
85  Grabber& operator=(Grabber&&) = default;
86 
87  /** \brief virtual destructor. */
88  #if defined(_MSC_VER)
89  virtual inline ~Grabber () noexcept {}
90  #else
91  virtual inline ~Grabber () noexcept = default;
92  #endif
93 
94  /** \brief registers a callback function/method to a signal with the corresponding signature
95  * \param[in] callback: the callback function/method
96  * \return Connection object, that can be used to disconnect the callback method from the signal again.
97  */
98  template<typename T> boost::signals2::connection
99  registerCallback (const std::function<T>& callback);
100 
101  /** \brief indicates whether a signal with given parameter-type exists or not
102  * \return true if signal exists, false otherwise
103  */
104  template<typename T> bool
105  providesCallback () const noexcept;
106 
107  /** \brief For devices that are streaming, the streams are started by calling this method.
108  * Trigger-based devices, just trigger the device once for each call of start.
109  */
110  virtual void
111  start () = 0;
112 
113  /** \brief For devices that are streaming, the streams are stopped.
114  * This method has no effect for triggered devices.
115  */
116  virtual void
117  stop () = 0;
118 
119  /** \brief For devices that are streaming, stopped streams are started and running stream are stopped.
120  * For triggered devices, the behavior is not defined.
121  * \return true if grabber is running / streaming. False otherwise.
122  */
123  inline bool
124  toggle ();
125 
126  /** \brief returns the name of the concrete subclass.
127  * \return the name of the concrete driver.
128  */
129  virtual std::string
130  getName () const = 0;
131 
132  /** \brief Indicates whether the grabber is streaming or not. This value is not defined for triggered devices.
133  * \return true if grabber is running / streaming. False otherwise.
134  */
135  virtual bool
136  isRunning () const = 0;
137 
138  /** \brief returns fps. 0 if trigger based. */
139  virtual float
140  getFramesPerSecond () const = 0;
141 
142  protected:
143 
144  virtual void
145  signalsChanged () { }
146 
147  template<typename T> boost::signals2::signal<T>*
148  find_signal () const noexcept;
149 
150  template<typename T> int
151  num_slots () const noexcept;
152 
153  template<typename T> void
154  disconnect_all_slots ();
155 
156  template<typename T> void
157  block_signal ();
158 
159  template<typename T> void
160  unblock_signal ();
161 
162  inline void
163  block_signals ();
164 
165  inline void
166  unblock_signals ();
167 
168  template<typename T> boost::signals2::signal<T>*
169  createSignal ();
170 
171  std::map<std::string, std::unique_ptr<boost::signals2::signal_base>> signals_;
172  std::map<std::string, std::vector<boost::signals2::connection> > connections_;
173  std::map<std::string, std::vector<boost::signals2::shared_connection_block> > shared_connections_;
174  } ;
175 
176  bool
177  Grabber::toggle ()
178  {
179  if (isRunning ())
180  {
181  stop ();
182  } else
183  {
184  start ();
185  }
186  return isRunning ();
187  }
188 
189  template<typename T> boost::signals2::signal<T>*
190  Grabber::find_signal () const noexcept
191  {
192  using Signal = boost::signals2::signal<T>;
193 
194  const auto signal_it = signals_.find (typeid (T).name ());
195  if (signal_it != signals_.end ())
196  {
197  return (static_cast<Signal*> (signal_it->second.get ()));
198  }
199  return nullptr;
200  }
201 
202  template<typename T> void
204  {
205  const auto signal = find_signal<T> ();
206  if (signal != nullptr)
207  {
208  signal->disconnect_all_slots ();
209  }
210  }
211 
212  template<typename T> void
214  {
215  if (connections_.find (typeid (T).name ()) != connections_.end ())
216  for (auto &connection : shared_connections_[typeid (T).name ()])
217  connection.block ();
218  }
219 
220  template<typename T> void
222  {
223  if (connections_.find (typeid (T).name ()) != connections_.end ())
224  for (auto &connection : shared_connections_[typeid (T).name ()])
225  connection.unblock ();
226  }
227 
228  void
230  {
231  for (const auto &signal : signals_)
232  for (auto &connection : shared_connections_[signal.first])
233  connection.block ();
234  }
235 
236  void
238  {
239  for (const auto &signal : signals_)
240  for (auto &connection : shared_connections_[signal.first])
241  connection.unblock ();
242  }
243 
244  template<typename T> int
245  Grabber::num_slots () const noexcept
246  {
247  const auto signal = find_signal<T> ();
248  if (signal != nullptr)
249  {
250  return static_cast<int> (signal->num_slots ());
251  }
252  return 0;
253  }
254 
255  template<typename T> boost::signals2::signal<T>*
257  {
258  using Signal = boost::signals2::signal<T>;
259  using Base = boost::signals2::signal_base;
260  // DefferedPtr serves 2 purposes:
261  // * allows MSVC to copy it around, can't do that with unique_ptr<T>
262  // * performs dynamic allocation only when required. If the key is found, this
263  // struct is a no-op, otherwise it allocates when implicit conversion operator
264  // is called inside emplace/try_emplace
265  struct DefferedPtr {
266  operator std::unique_ptr<Base>() const { return std::make_unique<Signal>(); }
267  };
268  // TODO: remove later for C++17 features: structured bindings and try_emplace
269  #ifdef __cpp_structured_bindings
270  const auto [iterator, success] =
271  #else
272  typename decltype(signals_)::const_iterator iterator;
273  bool success;
274  std::tie (iterator, success) =
275  #endif
276 
277  #ifdef __cpp_lib_map_try_emplace
278  signals_.try_emplace (
279  #else
280  signals_.emplace (
281  #endif
282  std::string (typeid (T).name ()), DefferedPtr ());
283  if (!success)
284  {
285  return nullptr;
286  }
287  return static_cast<Signal*> (iterator->second.get ());
288  }
289 
290  template<typename T> boost::signals2::connection
291  Grabber::registerCallback (const std::function<T> & callback)
292  {
293  const auto signal = find_signal<T> ();
294  if (signal == nullptr)
295  {
296  std::stringstream sstream;
297 
298  sstream << "no callback for type:" << typeid (T).name ();
299 
300  PCL_THROW_EXCEPTION (pcl::IOException, "[" << getName () << "] " << sstream.str ());
301  //return (boost::signals2::connection ());
302  }
303  boost::signals2::connection ret = signal->connect (callback);
304 
305  connections_[typeid (T).name ()].push_back (ret);
306  shared_connections_[typeid (T).name ()].push_back (boost::signals2::shared_connection_block (connections_[typeid (T).name ()].back (), false));
307  signalsChanged ();
308  return (ret);
309  }
310 
311  template<typename T> bool
312  Grabber::providesCallback () const noexcept
313  {
314  return find_signal<T> ();
315  }
316 
317 } // namespace
Grabber interface for PCL 1.x device drivers.
Definition: grabber.h:60
void block_signals()
Definition: grabber.h:229
Grabber(Grabber &&)=default
Move ctor.
void unblock_signal()
Definition: grabber.h:221
Grabber & operator=(Grabber &&)=default
Move assign operator.
bool providesCallback() const noexcept
indicates whether a signal with given parameter-type exists or not
Definition: grabber.h:312
boost::signals2::signal< T > * find_signal() const noexcept
Definition: grabber.h:190
Grabber(const Grabber &)=delete
No copy ctor since Grabber can't be copied.
int num_slots() const noexcept
Definition: grabber.h:245
boost::signals2::signal< T > * createSignal()
Definition: grabber.h:256
Grabber()=default
Default ctor.
Grabber & operator=(const Grabber &)=delete
No copy assign operator since Grabber can't be copied.
void unblock_signals()
Definition: grabber.h:237
virtual ~Grabber() noexcept=default
virtual destructor.
void disconnect_all_slots()
Definition: grabber.h:203
void block_signal()
Definition: grabber.h:213
boost::signals2::connection registerCallback(const std::function< T > &callback)
registers a callback function/method to a signal with the corresponding signature
Definition: grabber.h:291
An exception that is thrown during an IO error (typical read/write errors)
Definition: exceptions.h:179
Defines all the PCL and non-PCL macros used.
#define PCL_EXPORTS
Definition: pcl_macros.h:323