00001 #include <rtt/RTT.hpp>
00002 #include <rtt/plugin/ServicePlugin.hpp>
00003 #include <rtt/marsh/PropertyBagIntrospector.hpp>
00004
00005 #include <ros/ros.h>
00006 #include <stack>
00007
00008 using namespace RTT;
00009 using namespace std;
00010
00011 class RosParam: public RTT::Service
00012 {
00013 public:
00014 RosParam(TaskContext* owner) :
00015 Service("rosparam", owner)
00016 {
00017 addOperation("storeProperties", &RosParam::storeProperties, this) .doc(
00018 "Stores all properties of this component to the ros param server");
00019 addOperation("refreshProperties", &RosParam::refreshProperties, this).doc(
00020 "Refreshes all properties of this component from the ros param server");
00021 addOperation("storeProperty", &RosParam::storeProperty, this) .doc(
00022 "Stores one property of this component to the ros param server").arg(
00023 "param_name", "Name of the property.").arg("private",
00024 "true if parameter should be put in private namespace").arg(
00025 "relative",
00026 "true if parameter should be put in the relative (component name) namespace");
00027 addOperation("refreshProperty", &RosParam::refreshProperty, this) .doc(
00028 "Refreshes one property of this component from the ros param server").arg(
00029 "param_name", "Name of the property.").arg("private",
00030 "true if parameter should be found the private namespace").arg(
00031 "relative",
00032 "true if parameter should be found in the relative (component name) namespace");
00033 this->doc("Store component properties on the ROS parameter server or refresh them using values on the ROS parameter server");
00034 }
00035 private:
00036
00037 std::stack<XmlRpc::XmlRpcValue> value_stack;
00038
00039 bool storeProperties()
00040 {
00041 Property<PropertyBag> bag(getOwner()->getName(), "");
00042
00043 marsh::PropertyBagIntrospector pbi(bag.value());
00044 pbi.introspect(*this->getOwner()->properties());
00045 if (PropertyToXmlRpcValue(&bag))
00046 {
00047 bool retval = true;
00048 assert(!value_stack.empty());
00049 try
00050 {
00051 ros::param::set(string("~") + bag.getName(), value_stack.top());
00052 } catch (ros::InvalidNameException ex)
00053 {
00054 log(Error) << ex.what() << endlog();
00055 retval = false;
00056 }
00057 value_stack.pop();
00058 assert(value_stack.empty());
00059 return retval;
00060 }
00061 return false;
00062 }
00063 bool storeProperty(const string& prop_name, bool priv, bool rel)
00064 {
00065 base::PropertyBase* base = this->getOwner()->properties()->getProperty(
00066 prop_name);
00067 if (base == NULL)
00068 {
00069 log(Error) << this->getOwner()->getName()
00070 << " does not have a Property with name " << prop_name
00071 << endlog();
00072 return false;
00073 }
00074 string param_name;
00075 if (priv)
00076 param_name = "~";
00077 if (rel)
00078 param_name += this->getOwner()->getName() + string("/");
00079 param_name += base->getName();
00080 if (PropertyToXmlRpcValue(base))
00081 {
00082 bool retval = true;
00083 assert(!value_stack.empty());
00084 try
00085 {
00086 ros::param::set(param_name, value_stack.top());
00087 } catch (ros::InvalidNameException ex)
00088 {
00089 log(Error) << ex.what() << endlog();
00090 retval = false;
00091 }
00092 value_stack.pop();
00093 assert(value_stack.empty());
00094 return retval;
00095
00096 }
00097 else
00098 {
00099
00100 PropertyBag bag;
00101 bag.add(base);
00102
00103 PropertyBag decomposed_bag;
00104 marsh::PropertyBagIntrospector pbi(decomposed_bag);
00105 pbi.introspect(bag);
00106 if (PropertyToXmlRpcValue(decomposed_bag.getProperty(
00107 base->getName())))
00108 {
00109 bool retval = true;
00110 assert(!value_stack.empty());
00111 try
00112 {
00113 ros::param::set(param_name, value_stack.top());
00114 } catch (ros::InvalidNameException ex)
00115 {
00116 log(Error) << ex.what() << endlog();
00117 retval = false;
00118 }
00119 value_stack.pop();
00120 assert(value_stack.empty());
00121 return retval;
00122 }
00123 return false;
00124 }
00125 return false;
00126 }
00127
00128 bool PropertyToXmlRpcValue(base::PropertyBase* prop)
00129 {
00130 return PropertyToXmlRpcValue<bool> (
00131 dynamic_cast<Property<bool>*> (prop)) || PropertyToXmlRpcValue<
00132 int> (dynamic_cast<Property<int>*> (prop))
00133 || PropertyToXmlRpcValue<double> (
00134 dynamic_cast<Property<double>*> (prop))
00135 || PropertyToXmlRpcValue<string> (dynamic_cast<Property<
00136 std::string>*> (prop)) || PropertyToXmlRpcValue(
00137 dynamic_cast<Property<PropertyBag>*> (prop));
00138 }
00139
00140 template<class T>
00141 bool PropertyToXmlRpcValue(Property<T>* prop)
00142 {
00143 if (!prop)
00144 return false;
00145
00146 value_stack.push(XmlRpc::XmlRpcValue(prop->rvalue()));
00147 return true;
00148 }
00149
00150 bool PropertyToXmlRpcValue(Property<PropertyBag>* prop)
00151 {
00152 if (!prop)
00153 return false;
00154 PropertyBag& bag = prop->value();
00155 XmlRpc::XmlRpcValue dict;
00156 for (size_t i = 0; i < bag.size(); i++)
00157 {
00158 if (PropertyToXmlRpcValue(bag.getItem(i)))
00159 {
00160 if (!bag.getItem(i)->getName().empty() && bag.getType()
00161 != "array")
00162 dict[bag.getItem(i)->getName()] = value_stack.top();
00163 else
00164 dict[i] = value_stack.top();
00165 value_stack.pop();
00166 }
00167 }
00168 if (bag.size() == 0)
00169 log(Warning) << "Exporting empty property bag " << prop->getName()
00170 << endlog();
00171 value_stack.push(dict);
00172 return true;
00173 }
00174
00175 bool refreshProperties()
00176 {
00177 XmlRpc::XmlRpcValue rpcval;
00178 try
00179 {
00180 if (!ros::param::get(string("~") + this->getOwner()->getName(),
00181 rpcval))
00182 {
00183 log(Error)
00184 << "The parameter server does not have a Property with name "
00185 << this->getOwner()->getName() << endlog();
00186 return false;
00187 }
00188 } catch (ros::InvalidNameException ex)
00189 {
00190 log(Error) << ex.what() << endlog();
00191 return false;
00192 }
00193 Property<PropertyBag> bag(getOwner()->getName(), "");
00194
00195 marsh::PropertyBagIntrospector pbi(bag.value());
00196 pbi.introspect(*this->getOwner()->properties());
00197 for (PropertyBag::iterator it = bag.value().begin(); it
00198 != bag.value().end(); ++it)
00199 {
00200 if (rpcval.hasMember((*it)->getName()))
00201 {
00202 if (!XmlRpcValueToProperty(rpcval[(*it)->getName()], (*it)))
00203 log(Warning) << "Could not update Property "
00204 << (*it)->getName() << endlog();
00205 base::PropertyBase* base =
00206 this->getOwner()->properties()->getProperty(
00207 (*it)->getName());
00208 if (!base->getTypeInfo()->composeType((*it)->getDataSource(),
00209 base->getDataSource()))
00210 log(Warning)<<"Could not compose "<<base->getName()<<endlog();
00211 }
00212 else
00213 log(Warning) << "Could not find Property " << (*it)->getName()
00214 << endlog();
00215 }
00216 return true;
00217 }
00218
00219 bool refreshProperty(const string& prop_name, bool priv, bool rel)
00220 {
00221 base::PropertyBase* base = this->getOwner()->properties()->getProperty(
00222 prop_name);
00223 if (base == NULL)
00224 {
00225 log(Error) << this->getOwner()->getName()
00226 << " does not have a Property with name " << prop_name
00227 << endlog();
00228 return false;
00229 }
00230 string param_name;
00231 if (priv)
00232 param_name = "~";
00233 if (rel)
00234 param_name += this->getOwner()->getName() + string("/");
00235 param_name += base->getName();
00236 XmlRpc::XmlRpcValue rpcval;
00237 try
00238 {
00239 if (!ros::param::get(param_name, rpcval))
00240 {
00241 log(Error)
00242 << "The parameter server does not have a Property with name "
00243 << param_name << endlog();
00244 return false;
00245 }
00246 } catch (ros::InvalidNameException ex)
00247 {
00248 log(Error) << ex.what() << endlog();
00249 return false;
00250 }
00251 PropertyBag bag;
00252 bag.add(base);
00253
00254 PropertyBag decomposed_bag;
00255 marsh::PropertyBagIntrospector pbi(decomposed_bag);
00256 pbi.introspect(bag);
00257 if (!XmlRpcValueToProperty(rpcval, decomposed_bag.getProperty(
00258 base->getName())))
00259 return false;
00260 if (base->getTypeInfo()->composeType(decomposed_bag.getProperty(
00261 base->getName())->getDataSource(), base->getDataSource()))
00262 return true;
00263 return false;
00264 }
00265
00266 bool XmlRpcValueToProperty(XmlRpc::XmlRpcValue &val,
00267 base::PropertyBase* prop)
00268 {
00269 switch (val.getType())
00270 {
00271 case XmlRpc::XmlRpcValue::TypeBoolean:
00272 {
00273 Property<bool> tmp("");
00274 tmp.set(val);
00275 if (prop->refresh(&tmp))
00276 return true;
00277 return false;
00278 }
00279 case XmlRpc::XmlRpcValue::TypeDouble:
00280 {
00281 Property<double> tmp("");
00282 tmp.set(val);
00283 if (prop->refresh(&tmp))
00284 return true;
00285 return false;
00286 }
00287 case XmlRpc::XmlRpcValue::TypeInt:
00288 {
00289 Property<int> tmp("");
00290 tmp.set(val);
00291 if (prop->refresh(&tmp))
00292 return true;
00293 return false;
00294 }
00295 case XmlRpc::XmlRpcValue::TypeString:
00296 {
00297 Property<std::string> tmp("");
00298 tmp.set(val);
00299 if (prop->refresh(&tmp))
00300 return true;
00301 return false;
00302 }
00303 case XmlRpc::XmlRpcValue::TypeArray:
00304 {
00305 Property<PropertyBag> bag("");
00306 bag = prop;
00307 if (!bag.ready())
00308 return false;
00309 if (val.size() != (int) bag.value().size())
00310 return false;
00311 for (int i = 0; i < val.size(); i++)
00312 {
00313 if (!XmlRpcValueToProperty(val[i], bag.value().getItem(i)))
00314 return false;
00315 }
00316
00317 if (prop->getTypeInfo()->composeType(bag.getDataSource(),
00318 prop->getDataSource()))
00319 return true;
00320 return false;
00321 }
00322 case XmlRpc::XmlRpcValue::TypeStruct:
00323 {
00324 Property<PropertyBag> bag("");
00325 bag = prop;
00326 if (!bag.ready())
00327 return false;
00328 if (bag.value().empty())
00329 {
00330 log(Warning) << "Could not update " << prop->getName()
00331 << endlog();
00332 return false;
00333 }
00334 for (PropertyBag::iterator it = bag.value().begin(); it
00335 != bag.value().end(); ++it)
00336 {
00337 if (val.hasMember((*it)->getName()))
00338 {
00339 if (!XmlRpcValueToProperty(val[(*it)->getName()],
00340 bag.value().getProperty((*it)->getName())))
00341 log(Warning) << "Could not convert "
00342 << (*it)->getName() << " from XmlRpcValue"
00343 << endlog();
00344 }
00345 else
00346 log(Warning) << "Could not find " << (*it)->getName()
00347 << " in " << prop->getName() << endlog();
00348 }
00349
00350 if (prop->getTypeInfo()->composeType(bag.getDataSource(),
00351 prop->getDataSource()))
00352 return true;
00353 return false;
00354 }
00355 default:
00356 {
00357 log(Warning) << "Cannot handle the type of " << prop->getName()
00358 << endlog();
00359 return false;
00360 }
00361 }
00362 }
00363
00364 };
00365
00366
00367 ORO_SERVICE_NAMED_PLUGIN(RosParam, "rosparam")