00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef RTT_DYNAMIC_RECONFIGURE_SERVER_H
00037 #define RTT_DYNAMIC_RECONFIGURE_SERVER_H
00038
00039 #include <rtt/Service.hpp>
00040 #include <rtt/TaskContext.hpp>
00041 #include <rtt/os/Mutex.hpp>
00042 #include <rtt/Logger.hpp>
00043 #include <rtt/Operation.hpp>
00044 #include <rtt/OperationCaller.hpp>
00045
00046 #include <rtt/internal/DataSources.hpp>
00047 #include <rtt/internal/GlobalEngine.hpp>
00048
00049 #include <ros/ros.h>
00050
00051 #include <dynamic_reconfigure/Reconfigure.h>
00052 #include <dynamic_reconfigure/Config.h>
00053 #include <dynamic_reconfigure/ConfigDescription.h>
00054
00055 #include <rtt/rtt-config.h>
00056 #if !defined(RTT_VERSION_GTE)
00057 #define RTT_VERSION_GTE(major,minor,patch) \
00058 ((RTT_VERSION_MAJOR > major) || (RTT_VERSION_MAJOR == major && \
00059 (RTT_VERSION_MINOR > minor) || (RTT_VERSION_MINOR == minor && \
00060 (RTT_VERSION_PATCH >= patch))))
00061 #endif
00062
00063 namespace rtt_dynamic_reconfigure {
00064
00065 template <class ConfigType> class Server;
00066 typedef bool (UpdateCallbackSignature)(RTT::PropertyBag &bag, uint32_t level);
00067 typedef bool (UpdateCallbackConstSignature)(const RTT::PropertyBag &bag, uint32_t level);
00068 typedef void (NotifyCallbackSignature)(uint32_t level);
00069
00075 template <class ConfigType>
00076 struct Updater {
00077 virtual bool propertiesFromConfig(ConfigType &config, uint32_t level, RTT::PropertyBag &) { return false; }
00078 virtual bool configFromProperties(ConfigType &config, const RTT::PropertyBag &) { return false; }
00079 };
00080
00081 template <class ConfigType>
00082 struct dynamic_reconfigure_traits {
00083 typedef Server<ConfigType> ServerType;
00084
00091 static void getMin(ConfigType &min, const ServerType *) { min = ConfigType::__getMin__(); }
00092
00099 static void getMax(ConfigType &max, const ServerType *) { max = ConfigType::__getMax__(); }
00100
00107 static void getDefault(ConfigType &dflt, const ServerType *) { dflt = ConfigType::__getDefault__(); }
00108
00115 static dynamic_reconfigure::ConfigDescriptionPtr getDescriptionMessage(const ServerType *) { return dynamic_reconfigure::ConfigDescriptionPtr(new dynamic_reconfigure::ConfigDescription(ConfigType::__getDescriptionMessage__())); }
00116
00120 static const bool canRefresh = false;
00121
00127 static void refreshDescription(const ServerType *) {}
00128
00136 static void toMessage(ConfigType &config, dynamic_reconfigure::Config &message, const ServerType *) { config.__toMessage__(message); }
00137
00145 static void fromMessage(ConfigType &config, dynamic_reconfigure::Config &message, const ServerType *) { config.__fromMessage__(message); }
00146
00153 static void clamp(ConfigType &config, const ServerType *) { config.__clamp__(); }
00154
00161 static RTT::internal::AssignableDataSource<RTT::PropertyBag>::shared_ptr getDataSource(ConfigType &config, const ServerType *server) {
00162 RTT::internal::AssignableDataSource<RTT::PropertyBag>::shared_ptr ds(new RTT::internal::ValueDataSource<RTT::PropertyBag>());
00163 if (!server->updater()->propertiesFromConfig(config, ~0, ds->set()))
00164 ds.reset();
00165 return ds;
00166 }
00167 };
00168
00169 namespace {
00170 struct null_deleter {
00171 void operator()(const void *) const {}
00172 };
00173 }
00174
00175
00176 class DynamicReconfigureTestComponent;
00177
00182 template <class ConfigType>
00183 class Server : public RTT::Service
00184 {
00185 private:
00186 typedef Updater<ConfigType> UpdaterType;
00187 typedef dynamic_reconfigure_traits<ConfigType> traits;
00188 typedef boost::shared_ptr< Server<ConfigType> > shared_ptr;
00189
00190 RTT::os::MutexRecursive mutex_;
00191 ros::NodeHandle *node_handle_;
00192 ros::ServiceServer set_service_;
00193 ros::Publisher update_pub_;
00194 ros::Publisher descr_pub_;
00195
00196 ConfigType config_;
00197 ConfigType min_;
00198 ConfigType max_;
00199 ConfigType default_;
00200
00201 mutable boost::shared_ptr<UpdaterType> updater_;
00202 bool initialized_;
00203
00204 RTT::OperationCaller<UpdateCallbackSignature> update_callback_;
00205 RTT::OperationCaller<UpdateCallbackConstSignature> update_callback_const_;
00206 RTT::Operation<UpdateCallbackConstSignature> update_callback_default_impl_;
00207 RTT::OperationCaller<NotifyCallbackSignature> notify_callback_;
00208
00209 public:
00216 Server(const std::string &name, RTT::TaskContext *owner)
00217 : RTT::Service(name, owner)
00218 , node_handle_(0)
00219 , update_callback_default_impl_("updateProperties", &Server<ConfigType>::updatePropertiesDefaultImpl, this, RTT::OwnThread, owner->engine())
00220 {
00221 construct();
00222 }
00223
00229 Server(RTT::TaskContext *owner)
00230 : RTT::Service("reconfigure", owner)
00231 , node_handle_(0)
00232 , update_callback_default_impl_("updateProperties", &Server<ConfigType>::updatePropertiesDefaultImpl, this, RTT::OwnThread, owner->engine())
00233 {
00234 construct();
00235 }
00236
00241 virtual ~Server() {
00242 shutdown();
00243 }
00244
00250 const ConfigType &getConfig() const { return config_; }
00251
00257 void updateConfig(const ConfigType &config)
00258 {
00259 updateConfigInternal(config);
00260 }
00261
00267 void getConfigMax(ConfigType &max) const
00268 {
00269 max = max_;
00270 }
00271
00277 const ConfigType &getConfigMax() const { return max_; }
00278
00284 ConfigType &getConfigMax() { return max_; }
00285
00291 void getConfigMin(ConfigType &min) const
00292 {
00293 min = min_;
00294 }
00295
00301 const ConfigType &getConfigMin() const { return min_; }
00302
00308 ConfigType &getConfigMin() { return min_; }
00309
00315 void getConfigDefault(ConfigType &config) const
00316 {
00317 config = default_;
00318 }
00319
00325 const ConfigType &getConfigDefault() const { return default_; }
00326
00332 ConfigType &getConfigDefault() { return default_; }
00333
00339 void setConfigMax(const ConfigType &config)
00340 {
00341 max_ = config;
00342 PublishDescription();
00343 }
00344
00350 void setConfigMin(const ConfigType &config)
00351 {
00352 min_ = config;
00353 PublishDescription();
00354 }
00355
00361 void setConfigDefault(const ConfigType &config)
00362 {
00363 default_ = config;
00364 PublishDescription();
00365 }
00366
00372 dynamic_reconfigure::ConfigDescriptionPtr getDescriptionMessage() {
00373 dynamic_reconfigure::ConfigDescriptionPtr description_message = traits::getDescriptionMessage(this);
00374
00375
00376 traits::toMessage(max_, description_message->max, this);
00377 traits::toMessage(min_, description_message->min, this);
00378 traits::toMessage(default_, description_message->dflt, this);
00379
00380 return description_message;
00381 }
00382
00389 void advertise(std::string ns = std::string())
00390 {
00391
00392 shutdown();
00393
00394
00395 if (ns.empty()) {
00396 if (getOwner()->getName() == "Deployer")
00397 ns = "~";
00398 else
00399 ns = "~" + getOwner()->getName();
00400 }
00401
00402
00403 node_handle_ = new ros::NodeHandle(ns);
00404
00405
00406 set_service_ = node_handle_->advertiseService("set_parameters", &Server<ConfigType>::setConfigCallback, this);
00407 descr_pub_ = node_handle_->advertise<dynamic_reconfigure::ConfigDescription>("parameter_descriptions", 1, true);
00408 update_pub_ = node_handle_->advertise<dynamic_reconfigure::Config>("parameter_updates", 1, true);
00409
00410
00411 PublishDescription();
00412 updateConfigInternal(config_);
00413 }
00414
00419 void shutdown()
00420 {
00421 if (node_handle_) {
00422 node_handle_->shutdown();
00423 delete node_handle_;
00424 node_handle_ = 0;
00425 }
00426 }
00427
00433 bool updated()
00434 {
00435 ConfigType new_config = config_;
00436 if (!updater()->configFromProperties(new_config, *(getOwner()->properties()))) return false;
00437 updateConfig(new_config);
00438 return true;
00439 }
00440
00445 void refresh()
00446 {
00447 RTT::os::MutexLock lock(mutex_);
00448
00449
00450 traits::refreshDescription(this);
00451
00452
00453 traits::getMin(min_, this);
00454 traits::getMax(max_, this);
00455 traits::getDefault(default_, this);
00456
00457
00458 PublishDescription();
00459
00460
00461 this->properties()->remove(this->properties()->getProperty("min"));
00462 this->properties()->remove(this->properties()->getProperty("max"));
00463 this->properties()->remove(this->properties()->getProperty("default"));
00464 this->properties()->ownProperty(new RTT::Property<RTT::PropertyBag>("min", "Minimum values as published to dynamic_reconfigure clients", traits::getDataSource(min_, this)));
00465 this->properties()->ownProperty(new RTT::Property<RTT::PropertyBag>("max", "Maximum values as published to dynamic_reconfigure clients", traits::getDataSource(max_, this)));
00466 this->properties()->ownProperty(new RTT::Property<RTT::PropertyBag>("default", "Default values as published to dynamic_reconfigure clients", traits::getDataSource(default_, this)));
00467
00468
00469 config_ = ConfigType();
00470 traits::getDefault(config_, this);
00471 updater()->configFromProperties(config_, *(getOwner()->properties()));
00472 if (node_handle_)
00473 config_.__fromServer__(*node_handle_);
00474 traits::clamp(config_, this);
00475
00476
00477 RTT::PropertyBag init_config;
00478 updater()->propertiesFromConfig(config_, ~0, init_config);
00479
00480
00481 #if !RTT_VERSION_GTE(2,8,99)
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492 RTT::base::OperationCallerBase<UpdateCallbackSignature>::shared_ptr update_callback_impl = update_callback_.getOperationCallerImpl();
00493 if (update_callback_impl) {
00494 RTT::ExecutionEngine *engine = update_callback_impl->getMessageProcessor();
00495 if (update_callback_impl->isSend() && engine && engine->getThread() && engine->getThread()->isSelf()) {
00496 RTT::Logger::In in(this->getOwner()->getName() + "." + this->getName());
00497 RTT::log(RTT::Debug) << "calling my own updateProperties operation from refresh()" << RTT::endlog();
00498 update_callback_impl.reset(update_callback_impl->cloneI(engine));
00499 update_callback_impl->call(init_config, ~0);
00500 } else {
00501 update_callback_(init_config, ~0);
00502 }
00503 }
00504 RTT::base::OperationCallerBase<UpdateCallbackConstSignature>::shared_ptr update_callback_const_impl = update_callback_const_.getOperationCallerImpl();
00505 if (update_callback_const_impl) {
00506 RTT::ExecutionEngine *engine = update_callback_const_impl->getMessageProcessor();
00507 if (update_callback_const_impl->isSend() && engine && engine->getThread() && engine->getThread()->isSelf()) {
00508 RTT::Logger::In in(this->getOwner()->getName() + "." + this->getName());
00509 RTT::log(RTT::Debug) << "calling my own updateProperties operation from refresh()" << RTT::endlog();
00510 update_callback_const_impl.reset(update_callback_const_impl->cloneI(engine));
00511 update_callback_const_impl->call(init_config, ~0);
00512 } else {
00513 update_callback_const_(init_config, ~0);
00514 }
00515 }
00516 RTT::base::OperationCallerBase<NotifyCallbackSignature>::shared_ptr notify_callback_impl = notify_callback_.getOperationCallerImpl();
00517 if (notify_callback_impl) {
00518 RTT::ExecutionEngine *engine = notify_callback_impl->getMessageProcessor();
00519 if (notify_callback_impl->isSend() && engine && engine->getThread() && engine->getThread()->isSelf()) {
00520 RTT::Logger::In in(this->getOwner()->getName() + "." + this->getName());
00521 RTT::log(RTT::Debug) << "calling my own notifyPropertiesUpdate operation from refresh()" << RTT::endlog();
00522 notify_callback_impl.reset(notify_callback_impl->cloneI(engine));
00523 notify_callback_impl->call(~0);
00524 } else {
00525 notify_callback_(~0);
00526 }
00527 }
00528 #else
00529 if (update_callback_.ready()) {
00530 update_callback_(init_config, ~0);
00531 } else if (update_callback_const_.ready()) {
00532 update_callback_const_(init_config, ~0);
00533 }
00534 if (notify_callback_.ready()) {
00535 notify_callback_(~0);
00536 }
00537 #endif
00538
00539 updateConfigInternal(config_);
00540 }
00541
00547 UpdaterType *updater() const
00548 {
00549 if (!updater_) updater_.reset(new UpdaterType());
00550 return updater_.get();
00551 }
00552
00558 void setUpdater(UpdaterType *updater)
00559 {
00560 updater_.reset(updater, null_deleter());
00561 }
00562
00568 void setUpdateCallback(RTT::OperationInterfacePart *impl)
00569 {
00570 update_callback_ = impl;
00571 }
00572
00578 void setNotificationCallback(RTT::OperationInterfacePart *impl)
00579 {
00580 notify_callback_ = impl;
00581 }
00582
00583 private:
00584 void construct()
00585 {
00586 this->addOperation("advertise", &Server<ConfigType>::advertise, this)
00587 .doc("Advertise this dynamic_reconfigure server at the master.")
00588 .arg("namespace", "The namespace this server should be advertised in. Defaults to ~component.");
00589 this->addOperation("shutdown", &Server<ConfigType>::shutdown, this)
00590 .doc("Shutdown this dynamic_reconfigure server.");
00591 this->addOperation("updated", &Server<ConfigType>::updated, this)
00592 .doc("Notify the dynamic_reconfigure server that properties have been updated. This will update the GUI.");
00593
00594 this->addOperation("refresh", &Server<ConfigType>::refresh, this)
00595 .doc("Rediscover the owner's properties or update advertised min/max/default values. Call this operation after having added properties.");
00596
00597
00598 UpdaterType *updater = dynamic_cast<UpdaterType *>(getOwner());
00599 if (updater) setUpdater(updater);
00600
00601
00602 if (getOwner() && getOwner()->provides()->hasMember("updateProperties")) {
00603 RTT::OperationInterfacePart *op = getOwner()->provides()->getPart("updateProperties");
00604 if (boost::dynamic_pointer_cast< RTT::base::OperationCallerBase<UpdateCallbackSignature> >(op->getLocalOperation())) {
00605 update_callback_ = op;
00606 } else {
00607 update_callback_const_ = op;
00608 }
00609 } else {
00610 update_callback_const_ = update_callback_default_impl_.getOperationCaller();
00611 }
00612
00613
00614 if (getOwner() && getOwner()->provides()->hasMember("notifyPropertiesUpdate")) {
00615 notify_callback_ = getOwner()->provides()->getPart("notifyPropertiesUpdate");
00616 }
00617
00618
00619 update_callback_.setCaller(RTT::internal::GlobalEngine::Instance());
00620 update_callback_const_.setCaller(RTT::internal::GlobalEngine::Instance());
00621 notify_callback_.setCaller(RTT::internal::GlobalEngine::Instance());
00622
00623
00624 refresh();
00625 }
00626
00627 void PublishDescription() {
00628 if (!descr_pub_) return;
00629 descr_pub_.publish(getDescriptionMessage());
00630 }
00631
00632 friend class DynamicReconfigureTestComponent;
00633 bool setConfigCallback(dynamic_reconfigure::Reconfigure::Request &req,
00634 dynamic_reconfigure::Reconfigure::Response &rsp)
00635 {
00636 RTT::os::MutexLock lock(mutex_);
00637
00638 ConfigType new_config = config_;
00639 traits::fromMessage(new_config, req.config, this);
00640 traits::clamp(new_config, this);
00641 uint32_t level = config_.__level__(new_config);
00642
00643 RTT::PropertyBag bag;
00644 if (!updater()->propertiesFromConfig(new_config, level, bag)) return false;
00645 if (update_callback_.ready()) {
00646 if (!update_callback_(bag, level)) return false;
00647 updater()->configFromProperties(new_config, bag);
00648 } else if (update_callback_const_.ready()) {
00649 if (!update_callback_const_(bag, level)) return false;
00650 } else {
00651 return false;
00652 }
00653 if (notify_callback_.ready()) notify_callback_(level);
00654
00655 updateConfigInternal(new_config);
00656 new_config.__toMessage__(rsp.config);
00657 return true;
00658 }
00659
00660 void updateConfigInternal(const ConfigType &config)
00661 {
00662 RTT::os::MutexLock lock(mutex_);
00663 config_ = config;
00664 if (node_handle_)
00665 config_.__toServer__(*node_handle_);
00666 dynamic_reconfigure::Config msg;
00667 config_.__toMessage__(msg);
00668
00669 if (update_pub_)
00670 update_pub_.publish(msg);
00671 }
00672
00673 bool updatePropertiesDefaultImpl(const RTT::PropertyBag &bag, uint32_t)
00674 {
00675 return RTT::updateProperties(*(getOwner()->properties()), bag);
00676 }
00677 };
00678
00689 template <typename T, typename ValueType>
00690 bool setProperty(const std::string &name, RTT::PropertyBag &bag, ValueType &value)
00691 {
00692 if (bag.getProperty(name)) {
00693 RTT::Property<T> *prop = bag.getPropertyType<T>(name);
00694 if (!prop) {
00695 RTT::log(RTT::Error) << "Could not assign property '" << name << "': Property exists with a different type." << RTT::endlog();
00696 return false;
00697 }
00698
00699 prop->set() = value;
00700
00701 } else {
00702 if (boost::is_same<T,ValueType>::value) {
00703 bag.addProperty(name, value);
00704 } else {
00705 bag.ownProperty(new RTT::Property<T>(name, std::string(), value));
00706 }
00707 }
00708
00709 return true;
00710 }
00711
00722 template <typename T, typename ValueType>
00723 bool getProperty(const std::string &name, const RTT::PropertyBag &bag, ValueType &value)
00724 {
00725 RTT::Property<T> *prop = bag.getPropertyType<T>(name);
00726 if (!prop) {
00727 RTT::log(RTT::Error) << "Could not get property '" << name << "': No such property in the bag." << RTT::endlog();
00728 return false;
00729 }
00730
00731 value = prop->rvalue();
00732 return true;
00733 }
00734
00735 }
00736
00737 #define RTT_DYNAMIC_RECONFIGURE_SERVICE_PLUGIN(CONFIG, NAME) \
00738 extern "C" {\
00739 RTT_EXPORT bool loadRTTPlugin(RTT::TaskContext* tc); \
00740 bool loadRTTPlugin(RTT::TaskContext* tc) { \
00741 if (tc == 0) return true; \
00742 RTT::Service::shared_ptr sp( new rtt_dynamic_reconfigure::Server<CONFIG>(NAME, tc ) ); \
00743 return tc->provides()->addService( sp ); \
00744 } \
00745 RTT_EXPORT RTT::Service::shared_ptr createService(); \
00746 RTT::Service::shared_ptr createService() { \
00747 RTT::Service::shared_ptr sp( new rtt_dynamic_reconfigure::Server<CONFIG>( 0 ) ); \
00748 return sp; \
00749 } \
00750 RTT_EXPORT std::string getRTTPluginName(); \
00751 std::string getRTTPluginName() { \
00752 return NAME; \
00753 } \
00754 RTT_EXPORT std::string getRTTTargetName(); \
00755 std::string getRTTTargetName() { \
00756 return OROCOS_TARGET_NAME; \
00757 } \
00758 }
00759
00760 #endif // RTT_DYNAMIC_RECONFIGURE_SERVER_H