Orocos Real-Time Toolkit  2.5.0
DataFlowInterface.cpp
00001 /***************************************************************************
00002   tag: FMTC  Tue Mar 11 21:49:27 CET 2008  DataFlowInterface.cpp
00003 
00004                         DataFlowInterface.cpp -  description
00005                            -------------------
00006     begin                : Tue March 11 2008
00007     copyright            : (C) 2008 FMTC
00008     email                : peter.soetens@fmtc.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #include "DataFlowInterface.hpp"
00040 #include "Logger.hpp"
00041 #include "Service.hpp"
00042 #include "TaskContext.hpp"
00043 
00044 namespace RTT
00045 {
00046     using namespace detail;
00047 
00048     DataFlowInterface::DataFlowInterface(Service* parent /* = 0 */)
00049         : mservice(parent)
00050     {}
00051 
00052     DataFlowInterface::~DataFlowInterface() {
00053     }
00054 
00055     TaskContext* DataFlowInterface::getOwner() const {
00056         return mservice ? mservice->getOwner() : 0;
00057     }
00058 
00059     PortInterface& DataFlowInterface::addPort(PortInterface& port) {
00060         if ( !chkPtr("addPort", "PortInterface", &port) ) return port;
00061         this->addLocalPort(port);
00062         if (mservice && mservice->hasService( port.getName()) != 0) {
00063             log(Warning) <<"'addPort' "<< port.getName() << ": name already in use as Service. Replacing previous service with new one." <<endlog();
00064             mservice->removeService(port.getName());
00065         }
00066 
00067         if (!mservice) {
00068             log(Warning) <<"'addPort' "<< port.getName() << ": DataFlowInterface not given to parent. Not adding Service." <<endlog();
00069             return port;
00070         }
00071         Service::shared_ptr ms( this->createPortObject( port.getName()) );
00072         if ( ms )
00073             mservice->addService( ms );
00074         // END NOTE.
00075         return port;
00076     }
00077 
00078     PortInterface& DataFlowInterface::addLocalPort(PortInterface& port) {
00079         for ( Ports::iterator it(mports.begin());
00080               it != mports.end();
00081               ++it)
00082             if ( (*it)->getName() == port.getName() ) {
00083                 log(Warning) <<"'addPort' "<< port.getName() << ": name already in use. Disconnecting and replacing previous port with new one." <<endlog();
00084                 removePort( port.getName() );
00085                 break;
00086             }
00087 
00088         mports.push_back( &port );
00089         port.setInterface( this );
00090         return port;
00091     }
00092 
00093     InputPortInterface& DataFlowInterface::addEventPort(InputPortInterface& port, SlotFunction callback) {
00094         if ( !chkPtr("addEventPort", "PortInterface", &port) ) return port;
00095         this->addLocalEventPort(port, callback);
00096         if (mservice && mservice->hasService( port.getName()) != 0) {
00097             log(Warning) <<"'addPort' "<< port.getName() << ": name already in use as Service. Replacing previous service with new one." <<endlog();
00098             mservice->removeService(port.getName());
00099         }
00100 
00101         if (!mservice) {
00102             log(Warning) <<"'addPort' "<< port.getName() << ": DataFlowInterface not given to parent. Not adding Service." <<endlog();
00103             return port;
00104         }
00105         Service::shared_ptr ms( this->createPortObject( port.getName()) );
00106         if ( ms )
00107             mservice->addService( ms );
00108         return port;
00109     }
00110 
00111 #ifdef ORO_SIGNALLING_PORTS
00112     void DataFlowInterface::setupHandles() {
00113         for_each(handles.begin(), handles.end(), boost::bind(&Handle::connect, _1));
00114     }
00115 
00116     void DataFlowInterface::cleanupHandles() {
00117         for_each(handles.begin(), handles.end(), boost::bind(&Handle::disconnect, _1));
00118     }
00119 #else
00120     void DataFlowInterface::dataOnPort(base::PortInterface* port)
00121     {
00122         if ( mservice && mservice->getOwner() )
00123             mservice->getOwner()->dataOnPort(port);
00124     }
00125 #endif
00126 
00127     InputPortInterface& DataFlowInterface::addLocalEventPort(InputPortInterface& port, SlotFunction callback) {
00128         this->addLocalPort(port);
00129 
00130         if (mservice == 0 || mservice->getOwner() == 0) {
00131             log(Error) << "addLocalEventPort "<< port.getName() <<": DataFlowInterface not part of a TaskContext. Will not trigger any TaskContext nor register callback." <<endlog();
00132             return port;
00133         }
00134 
00135 #ifdef ORO_SIGNALLING_PORTS
00136         // setup synchronous callback, only purpose is to register that port fired and trigger the TC's engine.
00137         Handle h = port.getNewDataOnPortEvent()->connect(boost::bind(&TaskContext::dataOnPort, mservice->getOwner(), _1) );
00138         if (h) {
00139             log(Info) << mservice->getName() << " will be triggered when new data is available on InputPort " << port.getName() << endlog();
00140             handles.push_back(h);
00141         } else {
00142             log(Error) << mservice->getName() << " can't connect to event of InputPort " << port.getName() << endlog();
00143             return port;
00144         }
00145 #endif
00146         if (callback)
00147             mservice->getOwner()->dataOnPortCallback(&port,callback); // the handle will be deleted when the port is removed.
00148 
00149 #ifndef ORO_SIGNALLING_PORTS
00150         port.signalInterface(true);
00151 #endif
00152         return port;
00153     }
00154 
00155     void DataFlowInterface::removePort(const std::string& name) {
00156         for ( Ports::iterator it(mports.begin());
00157               it != mports.end();
00158               ++it)
00159             if ( (*it)->getName() == name ) {
00160                 if (mservice) {
00161                     mservice->removeService( name );
00162                     if (mservice->getOwner())
00163                         mservice->getOwner()->dataOnPortRemoved( *it );
00164                 }
00165                 (*it)->disconnect(); // remove all connections and callbacks.
00166                 mports.erase(it);
00167                 return;
00168             }
00169     }
00170 
00171     DataFlowInterface::Ports DataFlowInterface::getPorts() const {
00172         return mports;
00173     }
00174 
00175     DataFlowInterface::PortNames DataFlowInterface::getPortNames() const {
00176         std::vector<std::string> res;
00177         for ( Ports::const_iterator it(mports.begin());
00178               it != mports.end();
00179               ++it)
00180             res.push_back( (*it)->getName() );
00181         return res;
00182     }
00183 
00184     PortInterface* DataFlowInterface::getPort(const std::string& name) const {
00185         for ( Ports::const_iterator it(mports.begin());
00186               it != mports.end();
00187               ++it)
00188             if ( (*it)->getName() == name )
00189                 return *it;
00190         return 0;
00191     }
00192 
00193     std::string DataFlowInterface::getPortDescription(const std::string& name) const {
00194         for ( Ports::const_iterator it(mports.begin());
00195               it != mports.end();
00196               ++it)
00197             if ( (*it)->getName() == name )
00198                 return (*it)->getDescription();
00199         return "";
00200     }
00201 
00202     bool DataFlowInterface::setPortDescription(const std::string& name, const std::string description) {
00203         Service::shared_ptr srv = mservice->getService(name);
00204         if (srv) {
00205             srv->doc(description);
00206             return true;
00207         }
00208         return false;
00209     }
00210 
00211     Service* DataFlowInterface::createPortObject(const std::string& name) {
00212         PortInterface* p = this->getPort(name);
00213         if ( !p )
00214             return 0;
00215         Service* to = p->createPortObject();
00216         if (to) {
00217             std::string d = this->getPortDescription(name);
00218             if ( !d.empty() )
00219                 to->doc( d );
00220             else
00221                 to->doc("No description set for this Port. Use .doc() to document it.");
00222         }
00223         return to;
00224     }
00225 
00226     void DataFlowInterface::clear()
00227     {
00228         // remove TaskObjects:
00229         for ( Ports::iterator it(mports.begin());
00230               it != mports.end();
00231               ++it) {
00232             if (mservice)
00233                 mservice->removeService( (*it)->getName() );
00234         }
00235         mports.clear();
00236     }
00237 
00238     bool DataFlowInterface::chkPtr(const std::string & where, const std::string & name, const void *ptr)
00239     {
00240         if ( ptr == 0) {
00241             log(Error) << "You tried to add a null pointer in '"<< where << "' for the object '" << name << "'. Fix your code !"<< endlog();
00242             return false;
00243         }
00244         return true;
00245     }
00246 
00247 }