driver_node.h
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, 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 Willow Garage 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 // Author: Blaise Gassend
36 #ifndef __DRIVER_BASE__DRIVER_NODE_H__
37 #define __DRIVER_BASE__DRIVER_NODE_H__
38 
40 #include <self_test/self_test.h>
41 #include <ros/node_handle.h>
42 #include <boost/thread.hpp>
43 #include <boost/bind.hpp>
44 #include <driver_base/SensorLevels.h>
45 #include <signal.h>
46 #include <dynamic_reconfigure/server.h>
47 
48 namespace driver_base
49 {
50 
52 {
53 public:
54  static int ctrl_c_hit_count_;
55 
56  static void hupCalled(int sig)
57  {
58  ROS_WARN("Unexpected SIGHUP caught. Ignoring it.");
59  }
60 
61  static void sigCalled(int sig)
62  {
63  ctrl_c_hit_count_++;
64  }
65 };
66 
67 template <class DriverType>
68 int main(int argc, char **argv, std::string name)
69 {
72  ros::init(argc, argv, name);
73  //ros::init(argc, argv, name, ros::init_options::NoSigintHandler);
74  //signal(SIGINT, &AbstractDriverNode::sigCalled);
75  //signal(SIGTERM, &AbstractDriverNode::sigCalled);
76  signal(SIGHUP, &AbstractDriverNode::hupCalled);
77  ros::NodeHandle nh;
78  DriverType driver(nh);
79  return driver.spin();
81 }
82 
83 template <class Driver>
85 {
86 public:
87  //typedef char state_t;
88  typedef typename Driver::Config Config;
89 
90 protected:
91  // Hooks
92  virtual void addDiagnostics() = 0;
93  virtual void addStoppedTests() = 0;
94  virtual void addOpenedTests() = 0;
95  virtual void addRunningTests() = 0;
96  virtual void reconfigureHook(int level) = 0;
97 
98  // Helper classes
103 
105  dynamic_reconfigure::Server<Config> reconfigure_server_;
107  // driver_ declaration must precede reconfigure_server_ for constructor
108  // calling order reasons.
109 
110 private:
111  // Subscriber tracking
112  int num_subscribed_topics_; // Number of topics that have subscribers.
113 
114  //static const state_t DISABLED = 0;
115  //static const state_t LAZY_ON = 1;
116  //static const state_t ALWAYS_ON = 2;
117  //static const state_t SELF_TEST = 3;
118  //static const state_t EXITING = 4;
119 
120  //state_t state_;
121 
123 
125 
126  // The device
127  typedef typename Driver::state_t drv_state_t;
128 
130 
132 
133  void reconfigure(Config &config, uint32_t level)
134  {
136  ROS_DEBUG("Reconfigure called at level %x.", level);
137  boost::recursive_mutex::scoped_lock lock(driver_.mutex_);
138 
139  drv_state_t orig_state = driver_.getState();
140 
141  if ((level | driver_base::SensorLevels::RECONFIGURE_STOP) == level)
142  {
143  driver_.stop();
144  if (!driver_.isStopped())
145  ROS_ERROR("Failed to stop streaming before reconfiguring. Reconfiguration may fail.");
146  }
147 
148  if ((level | driver_base::SensorLevels::RECONFIGURE_CLOSE) == level)
149  {
150  driver_.close();
151  if (!driver_.isClosed())
152  ROS_ERROR("Failed to close device before reconfiguring. Reconfiguration may fail.");
153  }
154 
155  driver_.config_update(config, level);
156  config = driver_.config_;
157  reconfigureHook(level);
158 
159  driver_.goState(orig_state);
160 
161  /* Other errors will show up when this happens. No need to have it
162  * here.
163  if (driver_.getState() != orig_state)
164  {
165  ROS_ERROR("Failed to resume original device state after reconfiguring. The requested configuration may contain errors.");
166  }
167  */
168 
169  ROS_DEBUG("Reconfigure completed.");
170  }
171 
172 private:
173 /* void connectCallback(const ros::PublisherPtr &pub)
174  {
175  if (pub.numSubscribers == 1)
176  num_subscribed_topics_++;
177 
178  if (num_subscribed_topics_ == 1)
179  start();
180  }
181 
182  void disconnectCallback(const ros::PublisherPtr &pub)
183  {
184  if (pub.numSubscribers == 0)
185  num_subscribed_topics_++;
186 
187  if (num_subscribed_topics_ == 0)
188  stop();
189  }*/
190 
192  {
193  driver_status_diagnostic_.addTask(&driver_status_standard_diagnostic_);
194  diagnostic_.add(driver_status_diagnostic_);
195  addDiagnostics();
196  }
197 
199  {
200  if (driver_.isRunning())
201  stat.summary(0, "OK");
202  else
203  stat.summary(2, "not running");
204 
205  stat.add("Driver state:", driver_.getStateName());
206  stat.add("Latest status message:", driver_.getStatusMessage());
208  }
209 
211  {
212  self_test_.add( "Interruption Test", this, &DriverNode::interruptionTest );
213  addStoppedTests();
214  self_test_.add( "Connection Test", this, &DriverNode::openTest );
215  self_test_.add( "ID Test", this, &DriverNode::idTest );
216  addOpenedTests();
217  self_test_.add( "Start Streaming Test", this, &DriverNode::runTest );
218  addRunningTests();
219  self_test_.add( "Stop Streaming Test", this, &DriverNode::stopTest );
220  self_test_.add( "Disconnection Test", this, &DriverNode::closeTest );
221  self_test_.add( "Resume Activity", this, &DriverNode::resumeTest );
222  }
223 
225  {
226  pre_self_test_driver_state_ = driver_.getState();
227  driver_.goClosed();
228 
229  drv_state_t s = driver_.getState();
230 
231  if (num_subscribed_topics_ > 0)
232  status.summary(1, "There were active subscribers. Running of self test interrupted operations.");
233  else if (s != Driver::CLOSED)
234  status.summaryf(2, "Could not close device, currently in state %s.", Driver::getStateName(s).c_str());
235  else
236  status.summary(0, "No operation interrupted.");
237  }
238 
239  void reliableGoStateTest(diagnostic_updater::DiagnosticStatusWrapper &status, drv_state_t target_state)
240  {
241  const int max_tries = 5;
242  ROS_ASSERT(max_tries > 0);
243  int retries;
244  drv_state_t current_state;
245  for (retries = 0; retries < max_tries; retries++)
246  {
247  sleep(1);
248  driver_.goState(target_state);
249 
250  current_state = driver_.getState();
251  if (current_state == target_state)
252  break;
253  }
254 
255  std::string target_state_name = Driver::getStateName(target_state);
256  std::string current_state_name = Driver::getStateName(current_state);
257 
258  // We carefully avoid rechecking the state here, as it may have
259  // changed since we last checked. We aren't here to check that we
260  // stayed in the target state, just want to check that we made it
261  // there...
262  if (retries >= max_tries)
263  status.summaryf(2, "Failed to go to %s state despite %u retries, now in state %s.", target_state_name.c_str(), retries, current_state_name.c_str());
264  else if (retries)
265  status.summaryf(1, "Successfully went to state %s after %u retries.", target_state_name.c_str(), retries);
266  else
267  status.summaryf(0, "Successfully went to state %s.", target_state_name.c_str());
268  }
269 
271  {
272  reliableGoStateTest(status, Driver::OPENED);
273  }
274 
276  {
277  std::string ID = driver_.getID();
278  if (ID.compare(""))
279  {
280  status.summaryf(0, "Device ID is %s", ID.c_str());
281  self_test_.setID(ID);
282  }
283  else
284  status.summaryf(2, "Error reading Device ID");
285  }
286 
288  {
289  reliableGoStateTest(status, Driver::RUNNING);
290  }
291 
293  {
294  reliableGoStateTest(status, Driver::OPENED);
295  }
296 
298  {
299  reliableGoStateTest(status, Driver::CLOSED);
300  }
301 
303  {
304  reliableGoStateTest(status, pre_self_test_driver_state_);
305  }
306 
307 public:
308  virtual ~DriverNode() {}
309 
310  int spin()
311  {
312  prepareDiagnostics();
313  prepareSelfTests();
314  typename dynamic_reconfigure::Server<Config>::CallbackType f = boost::bind(&DriverNode::reconfigure, this, _1, _2);
315  reconfigure_server_.setCallback(f);
316 
317  ros_thread_.reset(new boost::thread(boost::bind(&ros::spin)));
319  assert(ros_thread_);
320 
321  driver_.goRunning();
322 
324  std::string last_status_message;
325  while (node_handle_.ok() && /*state_ != EXITING &&*/ !ctrl_c_hit_count_)
326  {
327  {
328  // Must lock here, otherwise operations like reconfigure will cause
329  // the test to pass, and an unnecessary restart will happen when the
330  // reconfigure is done.
331  boost::recursive_mutex::scoped_lock lock_(driver_.mutex_);
332 
333  if (!driver_.isRunning())
334  {
335  std::string new_status_message = driver_.getStatusMessage();
336  if ((last_status_message != new_status_message || driver_.getRecoveryComplete())
337  && !driver_.getStatusOk())
338  {
339  ROS_ERROR("%s", new_status_message.c_str());
340  driver_.clearRecoveryComplete();
341  last_status_message = new_status_message;
342  }
344  driver_.goClosed();
345  driver_.goRunning();
346  }
347 
348  diagnostic_.update();
349  self_test_.checkTest();
350  }
351  ros::WallDuration(0.1).sleep();
352  }
353 
354  driver_.goClosed();
355 
356  ros::shutdown();
357 
358  if (ros_thread_ && !ros_thread_->timed_join((boost::posix_time::milliseconds) 2000))
359  {
360  ROS_ERROR("ROS thread did not die after two seconds. Pretending that it did. This is probably a bad sign.");
361  }
362  ros_thread_.reset();
363 
364  return 0;
365  }
366 
368  node_handle_(nh),
369  private_node_handle_("~"),
370  self_test_(node_handle_),
371  diagnostic_(),
372  reconfigure_server_(driver_.mutex_, ros::NodeHandle("~")),
373  driver_status_diagnostic_("Driver Status"),
374  driver_status_standard_diagnostic_("Driver Status", boost::bind(&DriverNode::statusDiagnostic, this, _1))
375  {
376  num_subscribed_topics_ = 0;
377  exit_status_ = 0;
378 
379  // Defer most initialization to spin so that virtual calls in derived
380  // classes will succeed.
381  }
382 };
383 
385 
386 // @todo exit status.
387 // @todo take over ctrl_c.
388 
389 };
390 
391 #endif
void resumeTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:302
Driver::Config Config
Definition: driver_node.h:88
bool getRecoveryComplete()
Definition: driver.h:252
state_t getState()
Definition: driver.h:219
self_test::TestRunner self_test_
Definition: driver_node.h:101
void clearRecoveryComplete()
Definition: driver.h:257
static const state_t CLOSED
Definition: driver.h:100
void reliableGoStateTest(diagnostic_updater::DiagnosticStatusWrapper &status, drv_state_t target_state)
Definition: driver_node.h:239
static const state_t RUNNING
Definition: driver.h:102
diagnostic_updater::CompositeDiagnosticTask driver_status_diagnostic_
Definition: driver_node.h:106
bool getStatusOk()
Definition: driver.h:247
void runTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:287
f
void closeTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:297
void summary(unsigned char lvl, const std::string s)
dynamic_reconfigure::Server< Config > reconfigure_server_
Definition: driver_node.h:105
XmlRpcServer s
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void add(const std::string &name, TaskFunction f)
int main(int argc, char **argv, std::string name)
Definition: driver_node.h:68
static void hupCalled(int sig)
Definition: driver_node.h:56
diagnostic_updater::Updater diagnostic_
Definition: driver_node.h:102
bool isStopped()
Definition: driver.h:213
#define ROS_WARN(...)
void summaryf(unsigned char lvl, const char *format,...)
const std::string getStatusMessage()
Definition: driver.h:262
bool isRunning()
Definition: driver.h:198
bool sleep() const
bool goRunning()
Definition: driver.h:163
ros::NodeHandle private_node_handle_
Definition: driver_node.h:100
void interruptionTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:224
DriverNode(ros::NodeHandle &nh)
Definition: driver_node.h:367
void idTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:275
drv_state_t pre_self_test_driver_state_
Definition: driver_node.h:129
ROSCPP_DECL void spin()
static void sigCalled(int sig)
Definition: driver_node.h:61
const std::string getStateName()
Definition: driver.h:224
bool goState(state_t target)
Definition: driver.h:104
boost::recursive_mutex mutex_
Definition: driver.h:98
diagnostic_updater::FunctionDiagnosticTask driver_status_standard_diagnostic_
Definition: driver_node.h:131
boost::shared_ptr< boost::thread > ros_thread_
Definition: driver_node.h:122
void setID(std::string id)
ROSCPP_DECL void shutdown()
bool ok() const
void add(const std::string &key, const T &val)
Driver::state_t drv_state_t
Definition: driver_node.h:127
#define ROS_ASSERT(cond)
ros::NodeHandle node_handle_
Definition: driver_node.h:99
void stopTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:292
void openTest(diagnostic_updater::DiagnosticStatusWrapper &status)
Definition: driver_node.h:270
#define ROS_ERROR(...)
void statusDiagnostic(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: driver_node.h:198
static const state_t OPENED
Definition: driver.h:101
void reconfigure(Config &config, uint32_t level)
Definition: driver_node.h:133
virtual std::string getID()=0
#define ROS_DEBUG(...)


driver_base
Author(s): Blaise Gassend
autogenerated on Thu Apr 11 2019 02:07:21