mux.cpp
Go to the documentation of this file.
00001 
00002 // demux is a generic ROS topic demultiplexer: one input topic is fanned out
00003 // to 1 of N output topics. A service is provided to select between the outputs
00004 //
00005 // Copyright (C) 2009, Morgan Quigley
00006 //
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions are met:
00009 //   * Redistributions of source code must retain the above copyright notice,
00010 //     this list of conditions and the following disclaimer.
00011 //   * Redistributions in binary form must reproduce the above copyright
00012 //     notice, this list of conditions and the following disclaimer in the
00013 //     documentation and/or other materials provided with the distribution.
00014 //   * Neither the name of Stanford University nor the names of its
00015 //     contributors may be used to endorse or promote products derived from
00016 //     this software without specific prior written permission.
00017 //
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 // POSSIBILITY OF SUCH DAMAGE.
00030 
00031 
00032 #include <cstdio>
00033 #include <vector>
00034 #include <list>
00035 #include "ros/console.h"
00036 #include "std_msgs/String.h"
00037 #include "topic_tools/MuxSelect.h"
00038 #include "topic_tools/MuxAdd.h"
00039 #include "topic_tools/MuxList.h"
00040 #include "topic_tools/MuxDelete.h"
00041 #include "topic_tools/shape_shifter.h"
00042 #include "topic_tools/parse.h"
00043 #include <nodelet/nodelet.h>
00044 #include <pluginlib/class_list_macros.h>
00045 
00046 using std::string;
00047 using std::vector;
00048 using std::list;
00049 using namespace topic_tools;
00050 
00051 const static string g_none_topic = "__none";
00052 
00053 struct sub_info_t
00054 {
00055   ros::Subscriber sub;
00056   ShapeShifter* msg;
00057 };
00058 
00059 class MuxNodelet : public nodelet::Nodelet
00060 {
00061 public:
00062   ros::NodeHandle g_node;
00063   ros::NodeHandle g_pnh;
00064   bool g_advertised;
00065   string g_output_topic;
00066   ros::Publisher g_pub;
00067   ros::Publisher g_pub_selected;
00068   list<struct sub_info_t> g_subs;
00069   list<struct sub_info_t>::iterator g_selected;
00070   ros::ServiceServer ss;
00071   // New service
00072   ros::ServiceServer ss_select;
00073   ros::ServiceServer ss_add;
00074   ros::ServiceServer ss_list;
00075   ros::ServiceServer ss_del;
00076 
00077   MuxNodelet () :  g_advertised(false), g_selected(g_subs.end())
00078   {}
00079 
00080   //int main(int argc, char **argv)
00081   void onInit()
00082   {
00083 //    vector<string> args;
00084 //    ros::removeROSArgs(argc, (const char**)argv, args);
00085 //
00086 //    if (args.size() < 3)
00087 //    {
00088 //      printf("\nusage: mux OUT_TOPIC IN_TOPIC1 [IN_TOPIC2 [...]]\n\n");
00089 //      return 1;
00090 //    }
00091     ros::NodeHandle mux_nh = getNodeHandle();
00092     ros::NodeHandle nh_priv = getPrivateNodeHandle();
00093     std::string topic_name = "output";
00094     nh_priv.param("topic_name", topic_name, topic_name);
00095 
00096     ros::NodeHandle n;
00097     g_node = getMTNodeHandle();
00098     g_pnh = getMTPrivateNodeHandle();
00099     g_output_topic = topic_name;
00100     // Put our API into the "mux" namespace, which the user should usually remap
00101     //ros::NodeHandle mux_nh("mux");
00102     // Latched publisher for selected input topic name
00103     g_pub_selected = nh_priv.advertise<std_msgs::String> (string("selected"), 1, true);
00104     // Backward compatibility
00105     //ss = n.advertiseService(g_output_topic + string("_select"), &MuxNodelet::sel_srv_cb_dep, this);
00106     // New service
00107     ss_select = nh_priv.advertiseService(string("select"), &MuxNodelet::sel_srv_cb, this);
00108     ss_add = nh_priv.advertiseService(string("add"), &MuxNodelet::add_topic_cb, this);
00109     ss_list = nh_priv.advertiseService(string("list"), &MuxNodelet::list_topic_cb, this);
00110     ss_del = nh_priv.advertiseService(string("delete"), &MuxNodelet::del_topic_cb, this);
00111 //    for (size_t i = 0; i < topics.size(); i++)
00112 //    {
00113 //      struct sub_info_t sub_info;
00114 //      sub_info.msg = new ShapeShifter;
00115 //      sub_info.sub = n.subscribe<ShapeShifter> (topics[i], 10, boost::bind(&MuxNodelet::in_cb, _1, sub_info.msg));
00116 //      g_subs.push_back(sub_info);
00117 //    }
00118 //    g_selected = g_subs.begin(); // select first topic to start
00119 //    std_msgs::String t;
00120 //    t.data = g_selected->sub.getTopic();
00121 //    g_pub_selected.publish(t);
00122 //    ros::spin();
00123 //    for (list<struct sub_info_t>::iterator it = g_subs.begin(); it != g_subs.end(); ++it)
00124 //    {
00125 //      it->sub.shutdown();
00126 //      delete it->msg;
00127 //    }
00128 //
00129 //    g_subs.clear();
00130 //    return 0;
00131   }
00132 
00133   bool sel_srv_cb(topic_tools::MuxSelect::Request &req, topic_tools::MuxSelect::Response &res)
00134   {
00135     bool ret = false;
00136     if (g_selected != g_subs.end())
00137       res.prev_topic = g_selected->sub.getTopic();
00138     else
00139       res.prev_topic = string("");
00140     // see if it's the magical '__none' topic, in which case we open the circuit
00141     if (req.topic == g_none_topic)
00142     {
00143       ROS_INFO("mux selected to no input.");
00144       g_selected = g_subs.end();
00145       ret = true;
00146     }
00147     else
00148     {
00149       ROS_INFO("trying to switch mux to %s", req.topic.c_str());
00150       // spin through our vector of inputs and find this guy
00151       for (list<struct sub_info_t>::iterator it = g_subs.begin(); it != g_subs.end(); ++it)
00152       {
00153         if (ros::names::resolve(it->sub.getTopic()) == ros::names::resolve(req.topic))
00154         {
00155           g_selected = it;
00156           ROS_INFO("mux selected input: [%s]", it->sub.getTopic().c_str());
00157           ret = true;
00158         }
00159       }
00160     }
00161 
00162     if (ret)
00163     {
00164       std_msgs::String t;
00165       t.data = req.topic;
00166       g_pub_selected.publish(t);
00167     }
00168 
00169     return ret;
00170   }
00171 
00172   bool sel_srv_cb_dep(topic_tools::MuxSelect::Request &req, topic_tools::MuxSelect::Response &res)
00173   {
00174     ROS_WARN("the <topic>_select service is deprecated; use mux/select instead");
00175     return sel_srv_cb(req, res);
00176   }
00177 
00178   void in_cb(const boost::shared_ptr<ShapeShifter const>& msg, ShapeShifter* s)
00179   {
00180     if (!g_advertised)
00181     {
00182       ROS_INFO("advertising");
00183       g_pub = msg->advertise(g_pnh, g_output_topic, 10);
00184       g_advertised = true;
00185     }
00186     if (s == g_selected->msg)
00187       g_pub.publish(msg);
00188   }
00189 
00190   bool list_topic_cb(topic_tools::MuxList::Request& req, topic_tools::MuxList::Response& res)
00191   {
00192     for (list<struct sub_info_t>::iterator it = g_subs.begin(); it != g_subs.end(); ++it)
00193     {
00194       res.topics.push_back(it->sub.getTopic());
00195     }
00196 
00197     return true;
00198   }
00199 
00200   bool add_topic_cb(topic_tools::MuxAdd::Request& req, topic_tools::MuxAdd::Response& res)
00201   {
00202     // Check that it's not already in our list
00203     ROS_INFO("trying to add %s to mux", req.topic.c_str());
00204 
00205 
00206     // Can't add the __none topic
00207     if (req.topic == g_none_topic)
00208     {
00209       ROS_WARN("failed to add topic %s to mux, because it's reserved for special use", req.topic.c_str());
00210       return false;
00211     }
00212 
00213     // spin through our vector of inputs and find this guy
00214     for (list<struct sub_info_t>::iterator it = g_subs.begin(); it != g_subs.end(); ++it)
00215     {
00216       if (ros::names::resolve(it->sub.getTopic()) == ros::names::resolve(req.topic))
00217       {
00218         ROS_WARN("tried to add a topic that mux was already listening to: [%s]", it->sub.getTopic().c_str());
00219         return false;
00220       }
00221     }
00222 
00223     struct sub_info_t sub_info;
00224     sub_info.msg = new ShapeShifter;
00225     try
00226     {
00227       sub_info.sub = g_node.subscribe<ShapeShifter> (req.topic, 10, boost::bind(&MuxNodelet::in_cb, this, _1, sub_info.msg));
00228     }
00229     catch (ros::InvalidNameException& e)
00230     {
00231       ROS_WARN("failed to add topic %s to mux, because it's an invalid name: %s", req.topic.c_str(), e.what());
00232       delete sub_info.msg;
00233       return false;
00234     }
00235     g_subs.push_back(sub_info);
00236 
00237     ROS_INFO("added %s to mux", req.topic.c_str());
00238 
00239     return true;
00240   }
00241 
00242   bool del_topic_cb(topic_tools::MuxDelete::Request& req, topic_tools::MuxDelete::Response& res)
00243   {
00244     // Check that it's in our list
00245     ROS_INFO("trying to delete %s from mux", req.topic.c_str());
00246     // spin through our vector of inputs and find this guy
00247     for (list<struct sub_info_t>::iterator it = g_subs.begin(); it != g_subs.end(); ++it)
00248     {
00249       if (ros::names::resolve(it->sub.getTopic()) == ros::names::resolve(req.topic))
00250       {
00251         // Can't delete the currently selected input, #2863
00252         if (it == g_selected)
00253         {
00254           ROS_WARN("tried to delete currently selected topic %s from mux", req.topic.c_str());
00255           return false;
00256         }
00257         it->sub.shutdown();
00258         delete it->msg;
00259         g_subs.erase(it);
00260         ROS_INFO("deleted topic %s from mux", req.topic.c_str());
00261         return true;
00262       }
00263     }
00264 
00265     ROS_WARN("tried to delete non-subscribed topic %s from mux", req.topic.c_str());
00266     return false;
00267   }
00268 
00269 };
00270 PLUGINLIB_DECLARE_CLASS(starmac_tools, MuxNodelet, MuxNodelet, nodelet::Nodelet)
00271 ;
00272 


starmac_tools
Author(s): bouffard
autogenerated on Sun Jan 5 2014 11:38:35