auto_config.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2014, Intermodalics BVBA
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 Intermodalics BVBA 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 
36 #include <rtt/Property.hpp>
39 
40 #include <cassert>
41 #include <climits>
42 #include <cfloat>
43 
44 #include <boost/thread/locks.hpp>
45 
46 #include <dynamic_reconfigure/config_tools.h>
47 
48 namespace rtt_dynamic_reconfigure {
49 
50 using namespace dynamic_reconfigure;
51 
58  : public RTT::internal::AssignableDataSource<RTT::PropertyBag>
59 {
60 protected:
62 
63 public:
65 
66  typedef boost::intrusive_ptr<AutoConfigDataSource> shared_ptr;
67 
68  AutoConfigDataSource(const AutoConfig &data) : mdata(data) {}
70 
73 
74  void set( typename AssignableDataSource<RTT::PropertyBag>::param_t t ) { mdata = t; }
75  AutoConfig& set() { return mdata; }
76  const AutoConfig& rvalue() const { return mdata; }
77 
78  virtual AutoConfigDataSource* clone() const { return new AutoConfigDataSource(mdata); }
79 
80  /* copied from ValueDataSource<T>::copy() in DataSources.inl */
81  virtual AutoConfigDataSource* copy( std::map<const RTT::base::DataSourceBase*, RTT::base::DataSourceBase*>& replace ) const
82  {
83  // if somehow a copy exists, return the copy, otherwise return this (see Attribute copy)
84  if ( replace[this] != 0 ) {
85  assert ( dynamic_cast<AutoConfigDataSource*>( replace[this] ) == static_cast<AutoConfigDataSource*>( replace[this] ) );
86  return static_cast<AutoConfigDataSource*>( replace[this] );
87  }
88  // Other pieces in the code rely on insertion in the map :
89  replace[this] = const_cast<AutoConfigDataSource*>(this);
90  // return this instead of a copy.
91  return const_cast<AutoConfigDataSource*>(this);
92  }
93 
99  AutoConfigDataSource* ret = dynamic_cast< AutoConfigDataSource* >( dsb );
100  return ret;
101  }
102 };
103 
105  : parent(), id(), state()
106 {
107 }
108 
110  : parent(), id(), state()
111 {
112  this->fromProperties(bag);
113 }
114 
116 {
117 }
118 
119 // default type
120 template <typename T> struct PropertyTypeInfo {
121  typedef std::string dynamic_reconfigure_type;
122  static std::string getType() { return "str"; }
123  static bool hasLimits() { return false; }
124  static T getMin() { return std::numeric_limits<T>::lowest(); }
125  static T getMax() { return std::numeric_limits<T>::max(); }
126 };
127 
128 template <> struct PropertyTypeInfo<bool>
129 {
131  static std::string getType() { return "bool"; }
132  static bool hasLimits() { return false; }
133  static bool getMin() { return false; }
134  static bool getMax() { return true; }
135 };
136 
137 template <> struct PropertyTypeInfo<int>
138 {
140  static std::string getType() { return "int"; }
141  static bool hasLimits() { return true; }
142  static int getMin() { return INT_MIN; }
143  static int getMax() { return INT_MAX; }
144 };
145 
146 template <> struct PropertyTypeInfo<unsigned int>
147 {
149  static std::string getType() { return "int"; }
150  static bool hasLimits() { return true; }
151  static int getMin() { return 0; }
152  static int getMax() { return INT_MAX; }
153 };
154 
155 template <> struct PropertyTypeInfo<std::string>
156 {
157  typedef std::string dynamic_reconfigure_type;
158  static std::string getType() { return "str"; }
159  static bool hasLimits() { return false; }
160  static std::string getMin() { return ""; }
161  static std::string getMax() { return ""; }
162 };
163 
164 template <> struct PropertyTypeInfo<double>
165 {
166  typedef double dynamic_reconfigure_type;
167  static std::string getType() { return "double"; }
168  static bool hasLimits() { return true; }
169  static double getMin() { return -DBL_MAX; }
170  static double getMax() { return DBL_MAX; }
171 };
172 
173 template <> struct PropertyTypeInfo<float>
174 {
175  typedef double dynamic_reconfigure_type;
176  static std::string getType() { return "double"; }
177  static bool hasLimits() { return true; }
178  static double getMin() { return -FLT_MAX; }
179  static double getMax() { return FLT_MAX; }
180 };
181 
183 {
184  const RTT::Property<RTT::PropertyBag> *prop = dynamic_cast<const RTT::Property<RTT::PropertyBag> *>(pb);
185  if (!prop) return 0;
187  if (!ds) return 0;
188  return &(ds->set());
189 }
190 
191 template <typename T>
192 static bool propertyFromMessage(AutoConfig &config, Config &msg, const RTT::base::PropertyBase *sample, const std::string &param_name)
193 {
194  const RTT::Property<T> *sample_prop = dynamic_cast<const RTT::Property<T> *>(sample);
195  if (!sample_prop) return false;
196 
198  if (!ConfigTools::getParameter(msg, param_name, value)) return false;
199 
200  RTT::Property<T> *prop = config.getPropertyType<T>(sample->getName());
201  if (!prop) {
202  prop = sample_prop->create();
203  config.ownProperty(prop);
204  }
205  prop->set(value);
206  return true;
207 }
208 
209 bool AutoConfig::__fromMessage__(Config &msg, const AutoConfig &sample)
210 {
211  return __fromMessage__(*this, msg, sample);
212 }
213 
214 bool AutoConfig::__fromMessage__(AutoConfig &config, Config &msg, const AutoConfig &sample)
215 {
216  // get group state
217  config.prefix_ = sample.prefix_;
218  config.name = sample.name;
219  config.id = sample.id;
220  config.parent = sample.parent;
221  dynamic_reconfigure::ConfigTools::getGroupState(msg, config.name, config);
222 
223  // iterate over all properties in sample
224  bool result = true;
225  for(RTT::PropertyBag::const_iterator i = sample.begin(); i != sample.end(); ++i) {
226  std::string param_name = config.prefix_ + (*i)->getName();
227 
228  // For sub groups, add a sub config to *this and recurse...
229  const AutoConfig *sample_sub = getAutoConfigFromProperty(*i);
230  if (sample_sub) {
231  RTT::Property<RTT::PropertyBag> *sub = config.getPropertyType<RTT::PropertyBag>((*i)->getName());
233  if (sub) {
234  ds = AutoConfigDataSource::narrow(sub->getDataSource().get());
235  assert(ds->rvalue().getType() == sample_sub->getType());
236  } else {
237  ds = new AutoConfigDataSource();
238  ds->set().setType(sample_sub->getType());
239  }
240 
241  if (ds && __fromMessage__(ds->set(), msg, *sample_sub)) {
242  if (!sub) {
243  // new AutoConfigDataSource
244  if (!ds->rvalue().empty()) {
245  sub = new RTT::Property<RTT::PropertyBag>((*i)->getName(), (*i)->getDescription(), AutoConfigDataSource::shared_ptr(ds));
246  config.ownProperty(sub);
247  } else {
248  delete ds;
249  }
250  }
251  continue;
252  }
253  }
254 
255  // search parameter in Config message
256  bool param_found = false;
257  for(Config::_bools_type::const_iterator n = msg.bools.begin(); n != msg.bools.end(); ++n) {
258  if (n->name == param_name) param_found = true;
259  }
260  for(Config::_ints_type::const_iterator n = msg.ints.begin(); n != msg.ints.end(); ++n) {
261  if (n->name == param_name) param_found = true;
262  }
263  for(Config::_strs_type::const_iterator n = msg.strs.begin(); n != msg.strs.end(); ++n) {
264  if (n->name == param_name) param_found = true;
265  }
266  for(Config::_doubles_type::const_iterator n = msg.doubles.begin(); n != msg.doubles.end(); ++n) {
267  if (n->name == param_name) param_found = true;
268  }
269  if (!param_found) continue;
270 
271  // get parameter value from Config message
272  if (
273  propertyFromMessage<bool>(config, msg, *i, param_name) ||
274  propertyFromMessage<int>(config, msg, *i, param_name) ||
275  propertyFromMessage<unsigned int>(config, msg, *i, param_name) ||
276  propertyFromMessage<std::string>(config, msg, *i, param_name) ||
277  propertyFromMessage<double>(config, msg, *i, param_name) ||
278  propertyFromMessage<float>(config, msg, *i, param_name)
279  ) continue;
280 
281  result = false;
282  }
283 
284  return result;
285 }
286 
287 template <typename T>
288 static bool propertyToMessage(Config &msg, const RTT::base::PropertyBase *pb, const std::string &_prefix)
289 {
290  const RTT::Property<T> *prop = dynamic_cast<const RTT::Property<T> *>(pb);
291  if (!prop) return false;
292 
293  typename PropertyTypeInfo<T>::dynamic_reconfigure_type value = prop->get();
294  ConfigTools::appendParameter(msg, _prefix + pb->getName(), value);
295  return true;
296 }
297 
298 void AutoConfig::__toMessage__(Config &msg) const
299 {
300  __toMessage__(*this, msg);
301 }
302 
303 void AutoConfig::__toMessage__(const AutoConfig &config, Config &msg)
304 {
305  // add group state
306  dynamic_reconfigure::ConfigTools::appendGroup(msg, config.name, config.id, config.parent, config);
307 
308  // iterate over all properties
309  bool result = true;
310  for(RTT::PropertyBag::const_iterator i = config.begin(); i != config.end(); ++i) {
311  if (propertyToMessage<bool>(msg, *i, config.prefix_) ||
312  propertyToMessage<int>(msg, *i, config.prefix_) ||
313  propertyToMessage<unsigned int>(msg, *i, config.prefix_) ||
314  propertyToMessage<std::string>(msg, *i, config.prefix_) ||
315  propertyToMessage<double>(msg, *i, config.prefix_) ||
316  propertyToMessage<float>(msg, *i, config.prefix_)
317  ) continue;
318 
319  // test if *i has type AutoConfig
320  const AutoConfig *sub = getAutoConfigFromProperty(*i);
321  if (sub) {
322  __toMessage__(*sub, msg);
323  continue;
324  }
325 
326  result = false;
327  }
328 }
329 
331 {
332 
333 }
334 
336 {
337 
338 }
339 
341 {
342  const AutoConfig &min = server->getConfigMin();
343  const AutoConfig &max = server->getConfigMax();
344 
345  // TODO: clamp values
346 }
347 
348 uint32_t AutoConfig::__level__(const AutoConfig &config) const
349 {
350  return 0;
351 }
352 
354 {
355  RTT::PropertyBag composed;
356  if (!RTT::types::composePropertyBag(*this, composed)) return false;
357  return RTT::updateProperties(target, composed);
358 }
359 
361 {
362  RTT::PropertyBag decomposed;
363  if (!RTT::types::decomposePropertyBag(source, decomposed)) return false;
364 
365  for(RTT::PropertyBag::const_iterator i = decomposed.begin(); i != decomposed.end(); ++i) {
366  RTT::base::PropertyBase *pb = this->getProperty((*i)->getName());
367  if (pb) {
368  pb->update(*i);
369  continue;
370  }
371 
373  if (sub) {
375  ds->set().setType(sub->rvalue().getType());
376  this->ownProperty(new RTT::Property<RTT::PropertyBag>(sub->getName(), sub->getDescription(), ds));
377  continue;
378  } else {
379  this->ownProperty((*i)->clone());
380  }
381  }
382 
383  return true;
384 }
385 
386 template <typename T>
387 static bool buildParamDescription(const RTT::base::PropertyBase *pb, const std::string &prefix, Group::_parameters_type& params, AutoConfig& dflt, AutoConfig& min, AutoConfig& max)
388 {
389  const RTT::Property<T> *prop = dynamic_cast<const RTT::Property<T> *>(pb);
390  if (!prop) return false;
391 
392  ParamDescription param;
393  param.name = prefix + pb->getName();
394  param.type = PropertyTypeInfo<T>::getType();
395  param.description = pb->getDescription();
396  params.push_back(param);
397 
398  // get current value as default
399  if (!dflt.getProperty(pb->getName())) {
400  RTT::Property<T> *dflt_prop = prop->create();
401  dflt_prop->set(prop->get());
402  dflt.ownProperty(dflt_prop);
403  }
404 
405  // get minimum/maximum value
406  if (!min.getProperty(pb->getName())) {
407  RTT::Property<T> *min_prop = prop->create();
408  min_prop->set(PropertyTypeInfo<T>::getMin());
409  min.ownProperty(min_prop);
410  }
411  if (!max.getProperty(pb->getName())) {
412  RTT::Property<T> *max_prop = prop->create();
413  max_prop->set(PropertyTypeInfo<T>::getMax());
414  max.ownProperty(max_prop);
415  }
416 
417  return true;
418 }
419 
420 static void buildGroupDescription(RTT::TaskContext *owner, const RTT::PropertyBag &bag, ConfigDescription& config_description, AutoConfig& dflt, AutoConfig& min, AutoConfig& max, const std::string &prefix, const std::string &name, const std::string &type, int32_t parent, int32_t &id)
421 {
422  std::size_t group_index = config_description.groups.size();
423  config_description.groups.push_back(Group());
424 
425  Group &group = config_description.groups[group_index];
426  group.name = name.empty() ? "Default" : name;
427  group.type = type;
428  group.parent = parent;
429  group.id = id;
430 
431  dflt.prefix_ = prefix;
432  dflt.name = group.name;
433  dflt.type = group.type;
434  dflt.parent = group.parent;
435  dflt.id = group.id;
436  dflt.state = true;
437 
438  min.prefix_ = prefix;
439  min.name = group.name;
440  min.type = group.type;
441  min.parent = group.parent;
442  min.id = group.id;
443  min.state = true;
444 
445  max.prefix_ = prefix;
446  max.name = group.name;
447  max.type = group.type;
448  max.parent = group.parent;
449  max.id = group.id;
450  max.state = true;
451 
452  // for loop might invalidate group reference -> use index group_index instead
453  for(RTT::PropertyBag::const_iterator i = bag.begin(); i != bag.end(); ++i) {
454  if (buildParamDescription<bool>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
455  buildParamDescription<int>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
456  buildParamDescription<unsigned int>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
457  buildParamDescription<std::string>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
458  buildParamDescription<double>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
459  buildParamDescription<float>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max)
460  ) continue;
461 
462  const RTT::Property<RTT::PropertyBag> *sub = dynamic_cast<RTT::Property<RTT::PropertyBag> *>(*i);
463  if (sub) {
464  AutoConfig *sub_dflt = getAutoConfigFromProperty(dflt.getProperty(sub->getName()));
465  if (!sub_dflt) {
467  sub_dflt = &(ds->set());
468  sub_dflt->setType(sub->rvalue().getType());
470  }
471 
472  AutoConfig *sub_min = getAutoConfigFromProperty(min.getProperty(sub->getName()));
473  if (!sub_min) {
475  sub_min = &(ds->set());
476  sub_min->setType(sub->rvalue().getType());
477  min.ownProperty(new RTT::Property<RTT::PropertyBag>(sub->getName(), sub->getDescription(), ds));
478  }
479 
481  if (!sub_max) {
483  sub_max = &(ds->set());
484  sub_max->setType(sub->rvalue().getType());
486  }
487 
488  buildGroupDescription(owner, sub->rvalue(), config_description, *sub_dflt, *sub_min, *sub_max, prefix + sub->getName() + "__", prefix + sub->getName(), "", config_description.groups[group_index].id, ++id);
489  }
490  }
491 }
492 
493 std::map<const AutoConfig::ServerType *, AutoConfig::CachePtr> AutoConfig::cache_;
494 boost::shared_mutex AutoConfig::cache_mutex_;
495 
497 {
498  RTT::PropertyBag decomposed;
499  if (!RTT::types::decomposePropertyBag(*(owner->properties()), decomposed)) {
500  RTT::log(RTT::Error) << "Failed to decompose properties of '" << owner->getName() << "' for dynamic_reconfigure. Properties with custom types will not be available for reconfiguration." << RTT::endlog();
501  decomposed = *(owner->properties());
502  }
503 
504  boost::upgrade_lock<boost::shared_mutex> upgrade_lock(cache_mutex_);
505  if (upgrade_lock.owns_lock())
506  {
507  boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upgrade_lock);
508  CachePtr& cache = cache_[server];
509  if (!cache) cache.reset(new Cache());
510  cache->description_message_.reset(new ConfigDescription);
511  int32_t id = 0;
512  buildGroupDescription(owner, decomposed, *(cache->description_message_), cache->default_, cache->min_, cache->max_, "", "", "", 0, id);
513  }
514 }
515 
516 dynamic_reconfigure::ConfigDescriptionPtr AutoConfig::__getDescriptionMessage__(const ServerType *server)
517 {
518  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
519  if (!cache_.count(server)) buildCache(server, server->getOwner());
520  return cache_.at(server)->description_message_;
521 }
522 
524 {
525  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
526  if (!cache_.count(server)) buildCache(server, server->getOwner());
527  return cache_.at(server)->default_;
528 }
529 
531 {
532  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
533  if (!cache_.count(server)) buildCache(server, server->getOwner());
534  return cache_.at(server)->max_;
535 }
536 
538 {
539  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
540  if (!cache_.count(server)) buildCache(server, server->getOwner());
541  return cache_.at(server)->min_;
542 }
543 
545 {
546  buildCache(server, server->getOwner());
547 }
548 
549 } // namespace rtt_dynamic_reconfigure
virtual base::DataSourceBase::shared_ptr getDataSource() const
bool __fromMessage__(dynamic_reconfigure::Config &msg, const AutoConfig &sample)
bool updateProperties(RTT::PropertyBag &) const
TaskContext * getOwner() const
DataSourceType get() const
bool param(const std::string &param_name, T &param_val, const T &default_val)
void getConfigMin(ConfigType &min) const
Definition: server.h:291
iterator end()
Property< T > * getPropertyType(const std::string &name) const
void getConfigMax(ConfigType &max) const
Definition: server.h:267
bool updateProperties(PropertyBag &target, const PropertyBag &source)
const T & min(const T &a, const T &b)
static AutoConfig * getAutoConfigFromProperty(const RTT::base::PropertyBase *pb)
static bool propertyFromMessage(AutoConfig &config, Config &msg, const RTT::base::PropertyBase *sample, const std::string &param_name)
const std::string & getType() const
static dynamic_reconfigure::ConfigDescriptionPtr __getDescriptionMessage__(const ServerType *server)
void setType(const std::string &newtype)
bool RTT_API composePropertyBag(PropertyBag const &sourcebag, PropertyBag &target)
const_reference_t rvalue() const
void __fromServer__(const ros::NodeHandle &nh)
void __toMessage__(dynamic_reconfigure::Config &msg) const
static void buildGroupDescription(RTT::TaskContext *owner, const RTT::PropertyBag &bag, ConfigDescription &config_description, AutoConfig &dflt, AutoConfig &min, AutoConfig &max, const std::string &prefix, const std::string &name, const std::string &type, int32_t parent, int32_t &id)
const T & max(const T &a, const T &b)
bool ownProperty(base::PropertyBase *p)
bool fromProperties(const RTT::PropertyBag &)
bool RTT_API decomposePropertyBag(PropertyBag const &sourcebag, PropertyBag &target)
static AutoConfigDataSource * narrow(RTT::base::DataSourceBase *dsb)
Definition: auto_config.cpp:98
uint32_t __level__(const AutoConfig &config) const
static void buildCache(const ServerType *server, RTT::TaskContext *owner)
virtual AutoConfigDataSource * copy(std::map< const RTT::base::DataSourceBase *, RTT::base::DataSourceBase * > &replace) const
Definition: auto_config.cpp:81
RTT::internal::DataSource< RTT::PropertyBag >::result_t value() const
Definition: auto_config.cpp:72
static bool buildParamDescription(const RTT::base::PropertyBase *pb, const std::string &prefix, Group::_parameters_type &params, AutoConfig &dflt, AutoConfig &min, AutoConfig &max)
const std::string & getDescription() const
static const AutoConfig & __getDefault__(const ServerType *server)
static bool propertyToMessage(Config &msg, const RTT::base::PropertyBase *pb, const std::string &_prefix)
static const AutoConfig & __getMin__(const ServerType *server)
Properties::const_iterator const_iterator
virtual AutoConfigDataSource * clone() const
Definition: auto_config.cpp:78
base::PropertyBase * getProperty(const std::string &name) const
PropertyBag * properties()
static void __refreshDescription__(const ServerType *server)
void __clamp__(const ServerType *server)
const std::string & getName() const
static std::map< const ServerType *, CachePtr > cache_
Definition: auto_config.h:85
reference_t set()
static const AutoConfig & __getMax__(const ServerType *server)
boost::intrusive_ptr< AutoConfigDataSource > shared_ptr
Definition: auto_config.cpp:66
virtual Property< T > * create() const
void set(typename AssignableDataSource< RTT::PropertyBag >::param_t t)
Definition: auto_config.cpp:74
static Logger & log()
virtual bool update(const PropertyBase *other)=0
static Logger::LogFunction endlog()
virtual const std::string & getName() const
void __toServer__(const ros::NodeHandle &nh) const
iterator begin()
boost::call_traits< value_t >::param_type param_t
static boost::shared_mutex cache_mutex_
Definition: auto_config.h:86


rtt_dynamic_reconfigure
Author(s): Johannes Meyer
autogenerated on Sat Jun 8 2019 18:05:06