$search
00001 /* 00002 * Copyright (C) 2009, Willow Garage, Inc. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions are met: 00006 * * Redistributions of source code must retain the above copyright notice, 00007 * this list of conditions and the following disclaimer. 00008 * * Redistributions in binary form must reproduce the above copyright 00009 * notice, this list of conditions and the following disclaimer in the 00010 * documentation and/or other materials provided with the distribution. 00011 * * Neither the names of Willow Garage, Inc. nor the names of its 00012 * contributors may be used to endorse or promote products derived from 00013 * this software without specific prior written permission. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00017 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00019 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00020 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00021 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00023 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00024 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00025 * POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 #include "ros/param.h" 00029 #include "ros/master.h" 00030 #include "ros/xmlrpc_manager.h" 00031 #include "ros/this_node.h" 00032 #include "ros/names.h" 00033 00034 #include <ros/console.h> 00035 00036 #include <boost/thread/mutex.hpp> 00037 #include <boost/lexical_cast.hpp> 00038 00039 namespace ros 00040 { 00041 00042 namespace param 00043 { 00044 00045 typedef std::map<std::string, XmlRpc::XmlRpcValue> M_Param; 00046 M_Param g_params; 00047 boost::mutex g_params_mutex; 00048 S_string g_subscribed_params; 00049 00050 void set(const std::string &key, const XmlRpc::XmlRpcValue &v) 00051 { 00052 std::string mapped_key = ros::names::resolve(key); 00053 00054 XmlRpc::XmlRpcValue params, result, payload; 00055 params[0] = this_node::getName(); 00056 params[1] = mapped_key; 00057 params[2] = v; 00058 00059 { 00060 // Lock around the execute to the master in case we get a parameter update on this value between 00061 // executing on the master and setting the parameter in the g_params list. 00062 boost::mutex::scoped_lock lock(g_params_mutex); 00063 00064 if (master::execute("setParam", params, result, payload, true)) 00065 { 00066 // Update our cached params list now so that if get() is called immediately after param::set() 00067 // we already have the cached state and our value will be correct 00068 if (g_subscribed_params.find(mapped_key) != g_subscribed_params.end()) 00069 { 00070 g_params[mapped_key] = v; 00071 } 00072 } 00073 } 00074 } 00075 00076 void set(const std::string &key, const std::string &s) 00077 { 00078 // construct xmlrpc_c::value object of the std::string and 00079 // call param::set(key, xmlvalue); 00080 XmlRpc::XmlRpcValue v(s); 00081 ros::param::set(key, v); 00082 } 00083 00084 void set(const std::string &key, const char* s) 00085 { 00086 // construct xmlrpc_c::value object of the std::string and 00087 // call param::set(key, xmlvalue); 00088 std::string sxx = std::string(s); 00089 XmlRpc::XmlRpcValue v(sxx); 00090 ros::param::set(key, v); 00091 } 00092 00093 void set(const std::string &key, double d) 00094 { 00095 XmlRpc::XmlRpcValue v(d); 00096 ros::param::set(key, v); 00097 } 00098 00099 void set(const std::string &key, int i) 00100 { 00101 XmlRpc::XmlRpcValue v(i); 00102 ros::param::set(key, v); 00103 } 00104 00105 void set(const std::string& key, bool b) 00106 { 00107 XmlRpc::XmlRpcValue v(b); 00108 ros::param::set(key, v); 00109 } 00110 00111 bool has(const std::string &key) 00112 { 00113 XmlRpc::XmlRpcValue params, result, payload; 00114 params[0] = this_node::getName(); 00115 params[1] = ros::names::resolve(key); 00116 //params[1] = key; 00117 // We don't loop here, because validateXmlrpcResponse() returns false 00118 // both when we can't contact the master and when the master says, "I 00119 // don't have that param." 00120 if (!master::execute("hasParam", params, result, payload, false)) 00121 { 00122 return false; 00123 } 00124 00125 return payload; 00126 } 00127 00128 bool del(const std::string &key) 00129 { 00130 std::string mapped_key = ros::names::resolve(key); 00131 00132 { 00133 boost::mutex::scoped_lock lock(g_params_mutex); 00134 00135 S_string::iterator sub_it = g_subscribed_params.find(mapped_key); 00136 if (sub_it != g_subscribed_params.end()) 00137 { 00138 g_subscribed_params.erase(sub_it); 00139 00140 M_Param::iterator param_it = g_params.find(mapped_key); 00141 if (param_it != g_params.end()) 00142 { 00143 g_params.erase(param_it); 00144 } 00145 } 00146 } 00147 00148 XmlRpc::XmlRpcValue params, result, payload; 00149 params[0] = this_node::getName(); 00150 params[1] = mapped_key; 00151 // We don't loop here, because validateXmlrpcResponse() returns false 00152 // both when we can't contact the master and when the master says, "I 00153 // don't have that param." 00154 if (!master::execute("deleteParam", params, result, payload, false)) 00155 { 00156 return false; 00157 } 00158 00159 return true; 00160 } 00161 00162 bool getImpl(const std::string &key, XmlRpc::XmlRpcValue &v, bool use_cache) 00163 { 00164 std::string mapped_key = ros::names::resolve(key); 00165 00166 if (use_cache) 00167 { 00168 boost::mutex::scoped_lock lock(g_params_mutex); 00169 00170 if (g_subscribed_params.find(mapped_key) != g_subscribed_params.end()) 00171 { 00172 M_Param::iterator it = g_params.find(mapped_key); 00173 if (it != g_params.end()) 00174 { 00175 if (it->second.valid()) 00176 { 00177 ROS_DEBUG_NAMED("cached_parameters", "Using cached parameter value for key [%s]", mapped_key.c_str()); 00178 00179 v = it->second; 00180 return true; 00181 } 00182 else 00183 { 00184 ROS_DEBUG_NAMED("cached_parameters", "Cached parameter is invalid for key [%s]", mapped_key.c_str()); 00185 return false; 00186 } 00187 } 00188 } 00189 else 00190 { 00191 // parameter we've never seen before, register for update from the master 00192 if (g_subscribed_params.insert(mapped_key).second) 00193 { 00194 XmlRpc::XmlRpcValue params, result, payload; 00195 params[0] = this_node::getName(); 00196 params[1] = XMLRPCManager::instance()->getServerURI(); 00197 params[2] = mapped_key; 00198 00199 if (!master::execute("subscribeParam", params, result, payload, false)) 00200 { 00201 ROS_DEBUG_NAMED("cached_parameters", "Subscribe to parameter [%s]: call to the master failed", mapped_key.c_str()); 00202 g_subscribed_params.erase(mapped_key); 00203 use_cache = false; 00204 } 00205 else 00206 { 00207 ROS_DEBUG_NAMED("cached_parameters", "Subscribed to parameter [%s]", mapped_key.c_str()); 00208 } 00209 } 00210 } 00211 } 00212 00213 XmlRpc::XmlRpcValue params, result; 00214 params[0] = this_node::getName(); 00215 params[1] = mapped_key; 00216 00217 // We don't loop here, because validateXmlrpcResponse() returns false 00218 // both when we can't contact the master and when the master says, "I 00219 // don't have that param." 00220 bool ret = master::execute("getParam", params, result, v, false); 00221 00222 if (use_cache) 00223 { 00224 boost::mutex::scoped_lock lock(g_params_mutex); 00225 00226 ROS_DEBUG_NAMED("cached_parameters", "Caching parameter [%s] with value type [%d]", mapped_key.c_str(), v.getType()); 00227 g_params[mapped_key] = v; 00228 } 00229 00230 return ret; 00231 } 00232 00233 bool getImpl(const std::string &key, std::string &s, bool use_cache) 00234 { 00235 XmlRpc::XmlRpcValue v; 00236 if (!getImpl(key, v, use_cache)) 00237 return false; 00238 if (v.getType() != XmlRpc::XmlRpcValue::TypeString) 00239 return false; 00240 s = std::string(v); 00241 return true; 00242 } 00243 00244 bool getImpl(const std::string &key, double &d, bool use_cache) 00245 { 00246 XmlRpc::XmlRpcValue v; 00247 if (!getImpl(key, v, use_cache)) 00248 { 00249 return false; 00250 } 00251 00252 if (v.getType() == XmlRpc::XmlRpcValue::TypeInt) 00253 { 00254 d = (int)v; 00255 } 00256 else if (v.getType() != XmlRpc::XmlRpcValue::TypeDouble) 00257 { 00258 return false; 00259 } 00260 else 00261 { 00262 d = v; 00263 } 00264 00265 return true; 00266 } 00267 00268 bool getImpl(const std::string &key, int &i, bool use_cache) 00269 { 00270 XmlRpc::XmlRpcValue v; 00271 if (!getImpl(key, v, use_cache)) 00272 { 00273 return false; 00274 } 00275 00276 if (v.getType() == XmlRpc::XmlRpcValue::TypeDouble) 00277 { 00278 double d = v; 00279 00280 if (fmod(d, 1.0) < 0.5) 00281 { 00282 d = floor(d); 00283 } 00284 else 00285 { 00286 d = ceil(d); 00287 } 00288 00289 i = d; 00290 } 00291 else if (v.getType() != XmlRpc::XmlRpcValue::TypeInt) 00292 { 00293 return false; 00294 } 00295 else 00296 { 00297 i = v; 00298 } 00299 00300 return true; 00301 } 00302 00303 bool getImpl(const std::string &key, bool &b, bool use_cache) 00304 { 00305 XmlRpc::XmlRpcValue v; 00306 if (!getImpl(key, v, use_cache)) 00307 return false; 00308 if (v.getType() != XmlRpc::XmlRpcValue::TypeBoolean) 00309 return false; 00310 b = v; 00311 return true; 00312 } 00313 00314 bool get(const std::string& key, std::string& s) 00315 { 00316 return getImpl(key, s, false); 00317 } 00318 00319 bool get(const std::string& key, double& d) 00320 { 00321 return getImpl(key, d, false); 00322 } 00323 00324 bool get(const std::string& key, int& i) 00325 { 00326 return getImpl(key, i, false); 00327 } 00328 00329 bool get(const std::string& key, bool& b) 00330 { 00331 return getImpl(key, b, false); 00332 } 00333 00334 bool get(const std::string& key, XmlRpc::XmlRpcValue& v) 00335 { 00336 return getImpl(key, v, false); 00337 } 00338 00339 bool getCached(const std::string& key, std::string& s) 00340 { 00341 return getImpl(key, s, true); 00342 } 00343 00344 bool getCached(const std::string& key, double& d) 00345 { 00346 return getImpl(key, d, true); 00347 } 00348 00349 bool getCached(const std::string& key, int& i) 00350 { 00351 return getImpl(key, i, true); 00352 } 00353 00354 bool getCached(const std::string& key, bool& b) 00355 { 00356 return getImpl(key, b, true); 00357 } 00358 00359 bool getCached(const std::string& key, XmlRpc::XmlRpcValue& v) 00360 { 00361 return getImpl(key, v, true); 00362 } 00363 00364 bool search(const std::string& key, std::string& result_out) 00365 { 00366 return search(this_node::getName(), key, result_out); 00367 } 00368 00369 bool search(const std::string& ns, const std::string& key, std::string& result_out) 00370 { 00371 XmlRpc::XmlRpcValue params, result, payload; 00372 params[0] = ns; 00373 00374 // searchParam needs a separate form of remapping -- remapping on the unresolved name, rather than the 00375 // resolved one. 00376 00377 std::string remapped = key; 00378 M_string::const_iterator it = names::getUnresolvedRemappings().find(key); 00379 if (it != names::getUnresolvedRemappings().end()) 00380 { 00381 remapped = it->second; 00382 } 00383 00384 params[1] = remapped; 00385 // We don't loop here, because validateXmlrpcResponse() returns false 00386 // both when we can't contact the master and when the master says, "I 00387 // don't have that param." 00388 if (!master::execute("searchParam", params, result, payload, false)) 00389 { 00390 return false; 00391 } 00392 00393 result_out = (std::string)payload; 00394 00395 return true; 00396 } 00397 00398 void update(const std::string& key, const XmlRpc::XmlRpcValue& v) 00399 { 00400 std::string clean_key = names::clean(key); 00401 ROS_DEBUG_NAMED("cached_parameters", "Received parameter update for key [%s]", clean_key.c_str()); 00402 00403 boost::mutex::scoped_lock lock(g_params_mutex); 00404 00405 g_params[clean_key] = v; 00406 } 00407 00408 void paramUpdateCallback(XmlRpc::XmlRpcValue& params, XmlRpc::XmlRpcValue& result) 00409 { 00410 result[0] = 1; 00411 result[1] = std::string(""); 00412 result[2] = 0; 00413 00414 ros::param::update((std::string)params[1], params[2]); 00415 } 00416 00417 void init(const M_string& remappings) 00418 { 00419 M_string::const_iterator it = remappings.begin(); 00420 M_string::const_iterator end = remappings.end(); 00421 for (; it != end; ++it) 00422 { 00423 const std::string& name = it->first; 00424 const std::string& param = it->second; 00425 00426 if (name.size() < 2) 00427 { 00428 continue; 00429 } 00430 00431 if (name[0] == '_' && name[1] != '_') 00432 { 00433 std::string local_name = "~" + name.substr(1); 00434 00435 bool success = false; 00436 00437 try 00438 { 00439 int32_t i = boost::lexical_cast<int32_t>(param); 00440 ros::param::set(names::resolve(local_name), i); 00441 success = true; 00442 } 00443 catch (boost::bad_lexical_cast&) 00444 { 00445 00446 } 00447 00448 if (success) 00449 { 00450 continue; 00451 } 00452 00453 try 00454 { 00455 double d = boost::lexical_cast<double>(param); 00456 ros::param::set(names::resolve(local_name), d); 00457 success = true; 00458 } 00459 catch (boost::bad_lexical_cast&) 00460 { 00461 00462 } 00463 00464 if (success) 00465 { 00466 continue; 00467 } 00468 00469 if (param == "true" || param == "True" || param == "TRUE") 00470 { 00471 ros::param::set(names::resolve(local_name), true); 00472 } 00473 else if (param == "false" || param == "False" || param == "FALSE") 00474 { 00475 ros::param::set(names::resolve(local_name), false); 00476 } 00477 else 00478 { 00479 ros::param::set(names::resolve(local_name), param); 00480 } 00481 } 00482 } 00483 00484 XMLRPCManager::instance()->bind("paramUpdate", paramUpdateCallback); 00485 } 00486 00487 } // namespace param 00488 00489 } // namespace ros