auto_config.cpp
Go to the documentation of this file.
1 /*
2  * (C) 2014, Intermodalics BVBA
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the copyright holder nor the names of its contributors
13  * may be used to endorse or promote products derived from this software
14  * without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
31 #include <rtt/Property.hpp>
34 
35 #include <cassert>
36 #include <climits>
37 #include <cfloat>
38 
39 #include <boost/thread/locks.hpp>
40 
41 #include <dynamic_reconfigure/config_tools.h>
42 
43 namespace rtt_dynamic_reconfigure {
44 
45 using namespace dynamic_reconfigure;
46 
53  : public RTT::internal::AssignableDataSource<RTT::PropertyBag>
54 {
55 protected:
57 
58 public:
60 
61  typedef boost::intrusive_ptr<AutoConfigDataSource> shared_ptr;
62 
63  AutoConfigDataSource(const AutoConfig &data) : mdata(data) {}
65 
68 
69  void set( typename AssignableDataSource<RTT::PropertyBag>::param_t t ) { mdata = t; }
70  AutoConfig& set() { return mdata; }
71  const AutoConfig& rvalue() const { return mdata; }
72 
73  virtual AutoConfigDataSource* clone() const { return new AutoConfigDataSource(mdata); }
74 
75  /* copied from ValueDataSource<T>::copy() in DataSources.inl */
76  virtual AutoConfigDataSource* copy( std::map<const RTT::base::DataSourceBase*, RTT::base::DataSourceBase*>& replace ) const
77  {
78  // if somehow a copy exists, return the copy, otherwise return this (see Attribute copy)
79  if ( replace[this] != 0 ) {
80  assert ( dynamic_cast<AutoConfigDataSource*>( replace[this] ) == static_cast<AutoConfigDataSource*>( replace[this] ) );
81  return static_cast<AutoConfigDataSource*>( replace[this] );
82  }
83  // Other pieces in the code rely on insertion in the map :
84  replace[this] = const_cast<AutoConfigDataSource*>(this);
85  // return this instead of a copy.
86  return const_cast<AutoConfigDataSource*>(this);
87  }
88 
94  AutoConfigDataSource* ret = dynamic_cast< AutoConfigDataSource* >( dsb );
95  return ret;
96  }
97 };
98 
100  : parent(), id(), state()
101 {
102 }
103 
105  : parent(), id(), state()
106 {
107  this->fromProperties(bag);
108 }
109 
111 {
112 }
113 
114 // default type
115 template <typename T> struct PropertyTypeInfo {
116  typedef std::string dynamic_reconfigure_type;
117  static std::string getType() { return "str"; }
118  static bool hasLimits() { return false; }
119  static T getMin() { return std::numeric_limits<T>::lowest(); }
120  static T getMax() { return std::numeric_limits<T>::max(); }
121 };
122 
123 template <> struct PropertyTypeInfo<bool>
124 {
126  static std::string getType() { return "bool"; }
127  static bool hasLimits() { return false; }
128  static bool getMin() { return false; }
129  static bool getMax() { return true; }
130 };
131 
132 template <> struct PropertyTypeInfo<int>
133 {
135  static std::string getType() { return "int"; }
136  static bool hasLimits() { return true; }
137  static int getMin() { return INT_MIN; }
138  static int getMax() { return INT_MAX; }
139 };
140 
141 template <> struct PropertyTypeInfo<unsigned int>
142 {
144  static std::string getType() { return "int"; }
145  static bool hasLimits() { return true; }
146  static int getMin() { return 0; }
147  static int getMax() { return INT_MAX; }
148 };
149 
150 template <> struct PropertyTypeInfo<std::string>
151 {
152  typedef std::string dynamic_reconfigure_type;
153  static std::string getType() { return "str"; }
154  static bool hasLimits() { return false; }
155  static std::string getMin() { return ""; }
156  static std::string getMax() { return ""; }
157 };
158 
159 template <> struct PropertyTypeInfo<double>
160 {
161  typedef double dynamic_reconfigure_type;
162  static std::string getType() { return "double"; }
163  static bool hasLimits() { return true; }
164  static double getMin() { return -DBL_MAX; }
165  static double getMax() { return DBL_MAX; }
166 };
167 
168 template <> struct PropertyTypeInfo<float>
169 {
170  typedef double dynamic_reconfigure_type;
171  static std::string getType() { return "double"; }
172  static bool hasLimits() { return true; }
173  static double getMin() { return -FLT_MAX; }
174  static double getMax() { return FLT_MAX; }
175 };
176 
178 {
179  const RTT::Property<RTT::PropertyBag> *prop = dynamic_cast<const RTT::Property<RTT::PropertyBag> *>(pb);
180  if (!prop) return 0;
182  if (!ds) return 0;
183  return &(ds->set());
184 }
185 
186 template <typename T>
187 static bool propertyFromMessage(AutoConfig &config, Config &msg, const RTT::base::PropertyBase *sample, const std::string &param_name)
188 {
189  const RTT::Property<T> *sample_prop = dynamic_cast<const RTT::Property<T> *>(sample);
190  if (!sample_prop) return false;
191 
193  if (!ConfigTools::getParameter(msg, param_name, value)) return false;
194 
195  RTT::Property<T> *prop = config.getPropertyType<T>(sample->getName());
196  if (!prop) {
197  prop = sample_prop->create();
198  config.ownProperty(prop);
199  }
200  prop->set(value);
201  return true;
202 }
203 
204 bool AutoConfig::__fromMessage__(Config &msg, const AutoConfig &sample)
205 {
206  return __fromMessage__(*this, msg, sample);
207 }
208 
209 bool AutoConfig::__fromMessage__(AutoConfig &config, Config &msg, const AutoConfig &sample)
210 {
211  // get group state
212  config.prefix_ = sample.prefix_;
213  config.name = sample.name;
214  config.id = sample.id;
215  config.parent = sample.parent;
216  dynamic_reconfigure::ConfigTools::getGroupState(msg, config.name, config);
217 
218  // iterate over all properties in sample
219  bool result = true;
220  for(RTT::PropertyBag::const_iterator i = sample.begin(); i != sample.end(); ++i) {
221  std::string param_name = config.prefix_ + (*i)->getName();
222 
223  // For sub groups, add a sub config to *this and recurse...
224  const AutoConfig *sample_sub = getAutoConfigFromProperty(*i);
225  if (sample_sub) {
226  RTT::Property<RTT::PropertyBag> *sub = config.getPropertyType<RTT::PropertyBag>((*i)->getName());
228  if (sub) {
229  ds = AutoConfigDataSource::narrow(sub->getDataSource().get());
230  assert(ds->rvalue().getType() == sample_sub->getType());
231  } else {
232  ds = new AutoConfigDataSource();
233  ds->set().setType(sample_sub->getType());
234  }
235 
236  if (ds && __fromMessage__(ds->set(), msg, *sample_sub)) {
237  if (!sub) {
238  // new AutoConfigDataSource
239  if (!ds->rvalue().empty()) {
240  sub = new RTT::Property<RTT::PropertyBag>((*i)->getName(), (*i)->getDescription(), AutoConfigDataSource::shared_ptr(ds));
241  config.ownProperty(sub);
242  } else {
243  delete ds;
244  }
245  }
246  continue;
247  }
248  }
249 
250  // search parameter in Config message
251  bool param_found = false;
252  for(Config::_bools_type::const_iterator n = msg.bools.begin(); n != msg.bools.end(); ++n) {
253  if (n->name == param_name) param_found = true;
254  }
255  for(Config::_ints_type::const_iterator n = msg.ints.begin(); n != msg.ints.end(); ++n) {
256  if (n->name == param_name) param_found = true;
257  }
258  for(Config::_strs_type::const_iterator n = msg.strs.begin(); n != msg.strs.end(); ++n) {
259  if (n->name == param_name) param_found = true;
260  }
261  for(Config::_doubles_type::const_iterator n = msg.doubles.begin(); n != msg.doubles.end(); ++n) {
262  if (n->name == param_name) param_found = true;
263  }
264  if (!param_found) continue;
265 
266  // get parameter value from Config message
267  if (
268  propertyFromMessage<bool>(config, msg, *i, param_name) ||
269  propertyFromMessage<int>(config, msg, *i, param_name) ||
270  propertyFromMessage<unsigned int>(config, msg, *i, param_name) ||
271  propertyFromMessage<std::string>(config, msg, *i, param_name) ||
272  propertyFromMessage<double>(config, msg, *i, param_name) ||
273  propertyFromMessage<float>(config, msg, *i, param_name)
274  ) continue;
275 
276  result = false;
277  }
278 
279  return result;
280 }
281 
282 template <typename T>
283 static bool propertyToMessage(Config &msg, const RTT::base::PropertyBase *pb, const std::string &_prefix)
284 {
285  const RTT::Property<T> *prop = dynamic_cast<const RTT::Property<T> *>(pb);
286  if (!prop) return false;
287 
288  typename PropertyTypeInfo<T>::dynamic_reconfigure_type value = prop->get();
289  ConfigTools::appendParameter(msg, _prefix + pb->getName(), value);
290  return true;
291 }
292 
293 void AutoConfig::__toMessage__(Config &msg) const
294 {
295  __toMessage__(*this, msg);
296 }
297 
298 void AutoConfig::__toMessage__(const AutoConfig &config, Config &msg)
299 {
300  // add group state
301  dynamic_reconfigure::ConfigTools::appendGroup(msg, config.name, config.id, config.parent, config);
302 
303  // iterate over all properties
304  bool result = true;
305  for(RTT::PropertyBag::const_iterator i = config.begin(); i != config.end(); ++i) {
306  if (propertyToMessage<bool>(msg, *i, config.prefix_) ||
307  propertyToMessage<int>(msg, *i, config.prefix_) ||
308  propertyToMessage<unsigned int>(msg, *i, config.prefix_) ||
309  propertyToMessage<std::string>(msg, *i, config.prefix_) ||
310  propertyToMessage<double>(msg, *i, config.prefix_) ||
311  propertyToMessage<float>(msg, *i, config.prefix_)
312  ) continue;
313 
314  // test if *i has type AutoConfig
315  const AutoConfig *sub = getAutoConfigFromProperty(*i);
316  if (sub) {
317  __toMessage__(*sub, msg);
318  continue;
319  }
320 
321  result = false;
322  }
323 }
324 
326 {
327 
328 }
329 
331 {
332 
333 }
334 
336 {
337  const AutoConfig &min = server->getConfigMin();
338  const AutoConfig &max = server->getConfigMax();
339 
340  // TODO: clamp values
341 }
342 
343 uint32_t AutoConfig::__level__(const AutoConfig &config) const
344 {
345  return 0;
346 }
347 
349 {
350  RTT::PropertyBag composed;
351  if (!RTT::types::composePropertyBag(*this, composed)) return false;
352  return RTT::updateProperties(target, composed);
353 }
354 
356 {
357  RTT::PropertyBag decomposed;
358  if (!RTT::types::decomposePropertyBag(source, decomposed)) return false;
359 
360  for(RTT::PropertyBag::const_iterator i = decomposed.begin(); i != decomposed.end(); ++i) {
361  RTT::base::PropertyBase *pb = this->getProperty((*i)->getName());
362  if (pb) {
363  pb->update(*i);
364  continue;
365  }
366 
368  if (sub) {
370  ds->set().setType(sub->rvalue().getType());
371  this->ownProperty(new RTT::Property<RTT::PropertyBag>(sub->getName(), sub->getDescription(), ds));
372  continue;
373  } else {
374  this->ownProperty((*i)->clone());
375  }
376  }
377 
378  return true;
379 }
380 
381 template <typename T>
382 static bool buildParamDescription(const RTT::base::PropertyBase *pb, const std::string &prefix, Group::_parameters_type& params, AutoConfig& dflt, AutoConfig& min, AutoConfig& max)
383 {
384  const RTT::Property<T> *prop = dynamic_cast<const RTT::Property<T> *>(pb);
385  if (!prop) return false;
386 
387  ParamDescription param;
388  param.name = prefix + pb->getName();
389  param.type = PropertyTypeInfo<T>::getType();
390  param.description = pb->getDescription();
391  params.push_back(param);
392 
393  // get current value as default
394  if (!dflt.getProperty(pb->getName())) {
395  RTT::Property<T> *dflt_prop = prop->create();
396  dflt_prop->set(prop->get());
397  dflt.ownProperty(dflt_prop);
398  }
399 
400  // get minimum/maximum value
401  if (!min.getProperty(pb->getName())) {
402  RTT::Property<T> *min_prop = prop->create();
403  min_prop->set(PropertyTypeInfo<T>::getMin());
404  min.ownProperty(min_prop);
405  }
406  if (!max.getProperty(pb->getName())) {
407  RTT::Property<T> *max_prop = prop->create();
408  max_prop->set(PropertyTypeInfo<T>::getMax());
409  max.ownProperty(max_prop);
410  }
411 
412  return true;
413 }
414 
415 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)
416 {
417  std::size_t group_index = config_description.groups.size();
418  config_description.groups.push_back(Group());
419 
420  Group &group = config_description.groups[group_index];
421  group.name = name.empty() ? "Default" : name;
422  group.type = type;
423  group.parent = parent;
424  group.id = id;
425 
426  dflt.prefix_ = prefix;
427  dflt.name = group.name;
428  dflt.type = group.type;
429  dflt.parent = group.parent;
430  dflt.id = group.id;
431  dflt.state = true;
432 
433  min.prefix_ = prefix;
434  min.name = group.name;
435  min.type = group.type;
436  min.parent = group.parent;
437  min.id = group.id;
438  min.state = true;
439 
440  max.prefix_ = prefix;
441  max.name = group.name;
442  max.type = group.type;
443  max.parent = group.parent;
444  max.id = group.id;
445  max.state = true;
446 
447  // for loop might invalidate group reference -> use index group_index instead
448  for(RTT::PropertyBag::const_iterator i = bag.begin(); i != bag.end(); ++i) {
449  if (buildParamDescription<bool>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
450  buildParamDescription<int>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
451  buildParamDescription<unsigned int>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
452  buildParamDescription<std::string>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
453  buildParamDescription<double>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max) ||
454  buildParamDescription<float>(*i, prefix, config_description.groups[group_index].parameters, dflt, min, max)
455  ) continue;
456 
457  const RTT::Property<RTT::PropertyBag> *sub = dynamic_cast<RTT::Property<RTT::PropertyBag> *>(*i);
458  if (sub) {
459  AutoConfig *sub_dflt = getAutoConfigFromProperty(dflt.getProperty(sub->getName()));
460  if (!sub_dflt) {
462  sub_dflt = &(ds->set());
463  sub_dflt->setType(sub->rvalue().getType());
465  }
466 
467  AutoConfig *sub_min = getAutoConfigFromProperty(min.getProperty(sub->getName()));
468  if (!sub_min) {
470  sub_min = &(ds->set());
471  sub_min->setType(sub->rvalue().getType());
472  min.ownProperty(new RTT::Property<RTT::PropertyBag>(sub->getName(), sub->getDescription(), ds));
473  }
474 
476  if (!sub_max) {
478  sub_max = &(ds->set());
479  sub_max->setType(sub->rvalue().getType());
481  }
482 
483  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);
484  }
485  }
486 }
487 
488 std::map<const AutoConfig::ServerType *, AutoConfig::CachePtr> AutoConfig::cache_;
489 boost::shared_mutex AutoConfig::cache_mutex_;
490 
492 {
493  RTT::PropertyBag decomposed;
494  if (!RTT::types::decomposePropertyBag(*(owner->properties()), decomposed)) {
495  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();
496  decomposed = *(owner->properties());
497  }
498 
499  boost::upgrade_lock<boost::shared_mutex> upgrade_lock(cache_mutex_);
500  if (upgrade_lock.owns_lock())
501  {
502  boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upgrade_lock);
503  CachePtr& cache = cache_[server];
504  if (!cache) cache.reset(new Cache());
505  cache->description_message_.reset(new ConfigDescription);
506  int32_t id = 0;
507  buildGroupDescription(owner, decomposed, *(cache->description_message_), cache->default_, cache->min_, cache->max_, "", "", "", 0, id);
508  }
509 }
510 
511 dynamic_reconfigure::ConfigDescriptionPtr AutoConfig::__getDescriptionMessage__(const ServerType *server)
512 {
513  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
514  if (!cache_.count(server)) buildCache(server, server->getOwner());
515  return cache_.at(server)->description_message_;
516 }
517 
519 {
520  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
521  if (!cache_.count(server)) buildCache(server, server->getOwner());
522  return cache_.at(server)->default_;
523 }
524 
526 {
527  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
528  if (!cache_.count(server)) buildCache(server, server->getOwner());
529  return cache_.at(server)->max_;
530 }
531 
533 {
534  boost::shared_lock<boost::shared_mutex> lock(cache_mutex_);
535  if (!cache_.count(server)) buildCache(server, server->getOwner());
536  return cache_.at(server)->min_;
537 }
538 
540 {
541  buildCache(server, server->getOwner());
542 }
543 
544 } // 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:286
iterator end()
Property< T > * getPropertyType(const std::string &name) const
void getConfigMax(ConfigType &max) const
Definition: server.h:262
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:93
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:76
RTT::internal::DataSource< RTT::PropertyBag >::result_t value() const
Definition: auto_config.cpp:67
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:73
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:80
reference_t set()
static const AutoConfig & __getMax__(const ServerType *server)
boost::intrusive_ptr< AutoConfigDataSource > shared_ptr
Definition: auto_config.cpp:61
virtual Property< T > * create() const
void set(typename AssignableDataSource< RTT::PropertyBag >::param_t t)
Definition: auto_config.cpp:69
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:81


rtt_dynamic_reconfigure
Author(s): Johannes Meyer
autogenerated on Mon May 10 2021 02:44:56