driver.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 // Author: Blaise Gassend
00036 #ifndef __DRIVER_BASE__DRIVER_H__
00037 #define __DRIVER_BASE__DRIVER_H__
00038 
00039 #include <ros/ros.h>
00040 #include <boost/function.hpp>
00041 #include <boost/thread/recursive_mutex.hpp>
00042 #include <boost/thread/mutex.hpp>
00043 #include <stdarg.h>
00044 #include <cstdio>
00045 
00046 namespace driver_base
00047 {
00048 
00068 class Driver
00069 {
00070 public:  
00071   typedef char state_t;
00072 
00073 protected:
00074   state_t state_;
00075 
00076   virtual void doOpen() = 0;
00077   virtual void doClose() = 0;
00078   virtual void doStart() = 0;
00079   virtual void doStop() = 0;
00080 
00081   typedef boost::function< void() > hookFunction;
00082   hookFunction postOpenHook;
00083   
00084 private:  
00085   std::string status_message_;
00086   boost::mutex status_message_mutex_;
00087   bool status_ok_;
00088   bool status_recovery_complete_;
00089 
00090 public:
00091   void setPostOpenHook(hookFunction f)
00092   {
00093     postOpenHook = f;
00094   }
00095 
00096   virtual std::string getID() = 0;
00097   
00098   boost::recursive_mutex mutex_; 
00099 
00100   static const state_t CLOSED = 0; // Not connected to the hardware.
00101   static const state_t OPENED = 1; // Connected to the hardware, ready to start streaming.
00102   static const state_t RUNNING = 2; // Streaming data.
00103 
00104   bool goState(state_t target)
00105   {
00106     boost::recursive_mutex::scoped_lock lock(mutex_);
00107 
00108     if (state_ > target)
00109       return lowerState(target);
00110 
00111     if (state_ < target)
00112       return raiseState(target);
00113 
00114     return true;
00115   }
00116 
00117   bool raiseState(state_t target)
00118   {
00119     boost::recursive_mutex::scoped_lock lock(mutex_);
00120 
00121     switch (getState())  
00122     {
00123       case Driver::CLOSED:
00124         if (target <= Driver::CLOSED)
00125           return true;
00126         if (!tryTransition(Driver::OPENED, &Driver::doOpen))
00127           return false;
00128 
00129       case Driver::OPENED:
00130         if (target <= Driver::OPENED)
00131           return true;
00132         if (!tryTransition(Driver::RUNNING, &Driver::doStart))
00133           return false;
00134 
00135       default:
00136         return target <= getState();
00137     }
00138   }
00139 
00140   bool lowerState(state_t target)
00141   {
00142     boost::recursive_mutex::scoped_lock lock(mutex_);
00143 
00144     switch (getState())  
00145     {
00146       case Driver::RUNNING:
00147         if (target >= Driver::RUNNING)
00148           return true;
00149         if (!tryTransition(Driver::OPENED, &Driver::doStop))
00150           return false;
00151 
00152       case Driver::OPENED:
00153         if (target >= Driver::OPENED)
00154           return true;
00155         if (!tryTransition(Driver::CLOSED, &Driver::doClose))
00156           return false;
00157 
00158       default:
00159         return target >= getState();
00160     }
00161   }
00162 
00163   bool goRunning()
00164   {
00165     return goState(Driver::RUNNING);
00166   }
00167 
00168   bool goOpened()
00169   {
00170     return goState(Driver::OPENED);
00171   }
00172 
00173   bool goClosed()
00174   {
00175     return goState(Driver::CLOSED);
00176   }
00177 
00178   bool stop()
00179   {
00180     return lowerState(Driver::OPENED);
00181   }
00182 
00183   bool start()
00184   {
00185     return raiseState(Driver::RUNNING);
00186   }
00187   
00188   bool open()
00189   {
00190     return raiseState(Driver::OPENED);
00191   }
00192   
00193   bool close()
00194   {
00195     return lowerState(Driver::CLOSED);
00196   }
00197   
00198   bool isRunning()
00199   {
00200     return getState() == Driver::RUNNING;
00201   }
00202 
00203   bool isOpened()
00204   {
00205     return getState() == Driver::OPENED;
00206   }
00207 
00208   bool isClosed()
00209   {
00210     return getState() == Driver::CLOSED;
00211   }
00212   
00213   bool isStopped()
00214   {
00215     state_t s = getState();
00216     return s == Driver::CLOSED || s == Driver::OPENED;
00217   }
00218 
00219   state_t getState()
00220   {
00221     return state_;
00222   }
00223 
00224   const std::string getStateName()
00225   {
00226     return getStateName(state_);
00227   }
00228   
00229   static const std::string &getStateName(state_t s)
00230   {
00231     static const std::string names[4] = {
00232       std::string("CLOSED"),
00233       std::string("OPENED"),
00234       std::string("RUNNING"),
00235       std::string("Unknown")
00236     };
00237   
00238     if (s >= 0 && s <= 2)
00239       return names[(int) s];
00240     else
00241       return names[3];
00242   }
00243 
00244   Driver() : state_(CLOSED), status_ok_(false), status_recovery_complete_(false) {}
00245   virtual ~Driver() {}
00246 
00247   bool getStatusOk()
00248   {
00249     return status_ok_;
00250   }
00251   
00252   bool getRecoveryComplete()
00253   {
00254     return status_recovery_complete_;
00255   }
00256 
00257   void clearRecoveryComplete()
00258   {
00259     status_recovery_complete_ = false;
00260   }
00261   
00262   const std::string getStatusMessage()
00263   { // Not returning by reference for thread safety.
00264     boost::mutex::scoped_lock lock_(status_message_mutex_);
00265     return status_message_;
00266   }
00267 
00268   // Set ok to true if the status message is not an error.
00269   // Set recovery_complete if the device is now fully functioning, and any
00270   // subsequent error should be considered as an error.
00271   void setStatusMessage(const std::string &msg, bool ok = false, bool recovery_complete = false)
00272   {
00273     boost::mutex::scoped_lock lock_(status_message_mutex_);
00274     ROS_DEBUG("%s", msg.c_str());
00275     status_message_ = msg;
00276     status_ok_ = ok;
00277     status_recovery_complete_ |= recovery_complete;
00278   }
00279 
00280   void setStatusMessagef(const char *format, ...)
00281   {
00282     va_list va;
00283     char buff[1000]; // @todo This could be done more elegantly.
00284     va_start(va, format);
00285     if (vsnprintf(buff, sizeof(buff), format, va) >= (int) sizeof(buff))
00286       ROS_DEBUG("Really long string in Driver::setStatusMessagef, it was trunccated.");
00287     setStatusMessage(std::string(buff));
00288     va_end(va);
00289   }
00290 
00291 private:  
00292   const std::string &getTransitionName(void (Driver::*transition)())
00293   {
00294     static const std::string open = std::string("open");
00295     static const std::string close = std::string("close");
00296     static const std::string start = std::string("start");
00297     static const std::string stop = std::string("stop");
00298     static const std::string unknown = std::string("Unknown");
00299 
00300     if (transition == &Driver::doOpen)
00301       return open;
00302     if (transition == &Driver::doClose)
00303       return close;
00304     if (transition == &Driver::doStart)
00305       return start;
00306     if (transition == &Driver::doStop)
00307       return stop;
00308     
00309     return unknown;
00310   }
00311 
00312   bool tryTransition(state_t target, void (Driver::*transition)())
00313   {
00314     boost::recursive_mutex::scoped_lock lock_(mutex_);
00315     state_t orig = state_;
00316     ROS_DEBUG("Trying transition %s from %s to %s.", getTransitionName(transition).c_str(), getStateName(orig).c_str(), getStateName(target).c_str());
00317     try
00318     {
00319       (this->*transition)();
00320     }
00321     catch (...) 
00322     //catch (std::Exception e)
00323     {
00324       ROS_WARN("Caught exception in transition %s from %s to %s.\n", getTransitionName(transition).c_str(), getStateName(orig).c_str(), getStateName(target).c_str());
00325       //ROS_WARN("Caught exception in transition from %s to %s.\n%s", e.what(), getTransitionName(transition).c_str(), getStateName(orig).c_str(), getStateName(target).c_str());
00326     }
00327     bool out = state_ == target;
00328     if (out && transition == &Driver::doOpen)
00329       postOpenHook();
00330     ROS_DEBUG("Transition %s from %s to %s %s.", getTransitionName(transition).c_str(), getStateName(orig).c_str(), getStateName(target).c_str(), out ? "succeeded" : "failed");
00331     return out;
00332   }
00333 };
00334 
00336 
00337 };
00338 
00339 #endif
00340 


driver_base
Author(s): Blaise Gassend
autogenerated on Fri Jan 3 2014 11:19:50