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  virtual inline ~Grabber () noexcept = default;
89 
90  /** \brief registers a callback function/method to a signal with the corresponding signature
91  * \param[in] callback: the callback function/method
92  * \return Connection object, that can be used to disconnect the callback method from the signal again.
93  */
94  template<typename T> boost::signals2::connection
95  registerCallback (const std::function<T>& callback);
96 
97  /** \brief indicates whether a signal with given parameter-type exists or not
98  * \return true if signal exists, false otherwise
99  */
100  template<typename T> bool
101  providesCallback () const noexcept;
102 
103  /** \brief For devices that are streaming, the streams are started by calling this method.
104  * Trigger-based devices, just trigger the device once for each call of start.
105  */
106  virtual void
107  start () = 0;
108 
109  /** \brief For devices that are streaming, the streams are stopped.
110  * This method has no effect for triggered devices.
111  */
112  virtual void
113  stop () = 0;
114 
115  /** \brief For devices that are streaming, stopped streams are started and running stream are stopped.
116  * For triggered devices, the behavior is not defined.
117  * \return true if grabber is running / streaming. False otherwise.
118  */
119  inline bool
120  toggle ();
121 
122  /** \brief returns the name of the concrete subclass.
123  * \return the name of the concrete driver.
124  */
125  virtual std::string
126  getName () const = 0;
127 
128  /** \brief Indicates whether the grabber is streaming or not. This value is not defined for triggered devices.
129  * \return true if grabber is running / streaming. False otherwise.
130  */
131  virtual bool
132  isRunning () const = 0;
133 
134  /** \brief returns fps. 0 if trigger based. */
135  virtual float
136  getFramesPerSecond () const = 0;
137 
138  protected:
139 
140  virtual void
141  signalsChanged () { }
142 
143  template<typename T> boost::signals2::signal<T>*
144  find_signal () const noexcept;
145 
146  template<typename T> int
147  num_slots () const noexcept;
148 
149  template<typename T> void
150  disconnect_all_slots ();
151 
152  template<typename T> void
153  block_signal ();
154 
155  template<typename T> void
156  unblock_signal ();
157 
158  inline void
159  block_signals ();
160 
161  inline void
162  unblock_signals ();
163 
164  template<typename T> boost::signals2::signal<T>*
165  createSignal ();
166 
167  std::map<std::string, std::unique_ptr<boost::signals2::signal_base>> signals_;
168  std::map<std::string, std::vector<boost::signals2::connection> > connections_;
169  std::map<std::string, std::vector<boost::signals2::shared_connection_block> > shared_connections_;
170  } ;
171 
172  bool
173  Grabber::toggle ()
174  {
175  if (isRunning ())
176  {
177  stop ();
178  } else
179  {
180  start ();
181  }
182  return isRunning ();
183  }
184 
185  template<typename T> boost::signals2::signal<T>*
186  Grabber::find_signal () const noexcept
187  {
188  using Signal = boost::signals2::signal<T>;
189 
190  const auto signal_it = signals_.find (typeid (T).name ());
191  if (signal_it != signals_.end ())
192  {
193  return (static_cast<Signal*> (signal_it->second.get ()));
194  }
195  return nullptr;
196  }
197 
198  template<typename T> void
200  {
201  const auto signal = find_signal<T> ();
202  if (signal != nullptr)
203  {
204  signal->disconnect_all_slots ();
205  }
206  }
207 
208  template<typename T> void
210  {
211  if (connections_.find (typeid (T).name ()) != connections_.end ())
212  for (auto &connection : shared_connections_[typeid (T).name ()])
213  connection.block ();
214  }
215 
216  template<typename T> void
218  {
219  if (connections_.find (typeid (T).name ()) != connections_.end ())
220  for (auto &connection : shared_connections_[typeid (T).name ()])
221  connection.unblock ();
222  }
223 
224  void
226  {
227  for (const auto &signal : signals_)
228  for (auto &connection : shared_connections_[signal.first])
229  connection.block ();
230  }
231 
232  void
234  {
235  for (const auto &signal : signals_)
236  for (auto &connection : shared_connections_[signal.first])
237  connection.unblock ();
238  }
239 
240  template<typename T> int
241  Grabber::num_slots () const noexcept
242  {
243  const auto signal = find_signal<T> ();
244  if (signal != nullptr)
245  {
246  return static_cast<int> (signal->num_slots ());
247  }
248  return 0;
249  }
250 
251  template<typename T> boost::signals2::signal<T>*
253  {
254  using Signal = boost::signals2::signal<T>;
255  using Base = boost::signals2::signal_base;
256  // DefferedPtr serves 2 purposes:
257  // * allows MSVC to copy it around, can't do that with unique_ptr<T>
258  // * performs dynamic allocation only when required. If the key is found, this
259  // struct is a no-op, otherwise it allocates when implicit conversion operator
260  // is called inside emplace/try_emplace
261  struct DefferedPtr {
262  operator std::unique_ptr<Base>() const { return std::make_unique<Signal>(); }
263  };
264  // TODO: remove later for C++17 features: structured bindings and try_emplace
265  #ifdef __cpp_structured_bindings
266  const auto [iterator, success] =
267  #else
268  typename decltype(signals_)::const_iterator iterator;
269  bool success;
270  std::tie (iterator, success) =
271  #endif
272 
273  #ifdef __cpp_lib_map_try_emplace
274  signals_.try_emplace (
275  #else
276  signals_.emplace (
277  #endif
278  std::string (typeid (T).name ()), DefferedPtr ());
279  if (!success)
280  {
281  return nullptr;
282  }
283  return static_cast<Signal*> (iterator->second.get ());
284  }
285 
286  template<typename T> boost::signals2::connection
287  Grabber::registerCallback (const std::function<T> & callback)
288  {
289  const auto signal = find_signal<T> ();
290  if (signal == nullptr)
291  {
292  std::stringstream sstream;
293 
294  sstream << "no callback for type:" << typeid (T).name ();
295 
296  PCL_THROW_EXCEPTION (pcl::IOException, "[" << getName () << "] " << sstream.str ());
297  //return (boost::signals2::connection ());
298  }
299  boost::signals2::connection ret = signal->connect (callback);
300 
301  connections_[typeid (T).name ()].push_back (ret);
302  shared_connections_[typeid (T).name ()].push_back (boost::signals2::shared_connection_block (connections_[typeid (T).name ()].back (), false));
303  signalsChanged ();
304  return (ret);
305  }
306 
307  template<typename T> bool
308  Grabber::providesCallback () const noexcept
309  {
310  return find_signal<T> ();
311  }
312 
313 } // namespace
Grabber interface for PCL 1.x device drivers.
Definition: grabber.h:60
void block_signals()
Definition: grabber.h:225
Grabber(Grabber &&)=default
Move ctor.
void unblock_signal()
Definition: grabber.h:217
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:308
boost::signals2::signal< T > * find_signal() const noexcept
Definition: grabber.h:186
Grabber(const Grabber &)=delete
No copy ctor since Grabber can't be copied.
int num_slots() const noexcept
Definition: grabber.h:241
boost::signals2::signal< T > * createSignal()
Definition: grabber.h:252
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:233
virtual ~Grabber() noexcept=default
virtual destructor.
void disconnect_all_slots()
Definition: grabber.h:199
void block_signal()
Definition: grabber.h:209
boost::signals2::connection registerCallback(const std::function< T > &callback)
registers a callback function/method to a signal with the corresponding signature
Definition: grabber.h:287
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