Orocos Real-Time Toolkit  2.8.3
DataFlowInterface.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: FMTC Tue Mar 11 21:49:27 CET 2008 DataFlowInterface.cpp
3 
4  DataFlowInterface.cpp - description
5  -------------------
6  begin : Tue March 11 2008
7  copyright : (C) 2008 FMTC
8  email : peter.soetens@fmtc.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #include "DataFlowInterface.hpp"
40 #include "Logger.hpp"
41 #include "Service.hpp"
42 #include "TaskContext.hpp"
43 
44 namespace RTT
45 {
46  using namespace detail;
47 
49  : mservice(parent)
50  {}
51 
53  }
54 
56  return mservice ? mservice->getOwner() : 0;
57  }
58 
60  if ( !chkPtr("addPort", "PortInterface", &port) ) return port;
61  this->addLocalPort(port);
62  Service::shared_ptr mservice_ref;
63  if (mservice && mservice->hasService( port.getName()) ) {
64  // Since there is at least one child service, mservice is ref counted. The danger here is that mservice is destructed during removeService()
65  // for this reason, we take a ref to mservice until we leave addPort.
66  mservice_ref = mservice->provides(); // uses shared_from_this()
67  log(Warning) <<"'addPort' "<< port.getName() << ": name already in use as Service. Replacing previous service with new one." <<endlog();
69  }
70 
71  if (!mservice) {
72  log(Warning) <<"'addPort' "<< port.getName() << ": DataFlowInterface not given to parent. Not adding Service." <<endlog();
73  return port;
74  }
75  Service::shared_ptr ms( this->createPortObject( port.getName()) );
76  if ( ms )
77  mservice->addService( ms );
78  // END NOTE.
79  return port;
80  }
81 
83  for ( Ports::iterator it(mports.begin());
84  it != mports.end();
85  ++it)
86  if ( (*it)->getName() == port.getName() ) {
87  log(Warning) <<"'addPort' "<< port.getName() << ": name already in use. Disconnecting and replacing previous port with new one." <<endlog();
88  removeLocalPort( port.getName() );
89  break;
90  }
91 
92  mports.push_back( &port );
93  port.setInterface( this );
94  return port;
95  }
96 
98  if ( !chkPtr("addEventPort", "PortInterface", &port) ) return port;
99  this->addLocalEventPort(port, callback);
100  Service::shared_ptr mservice_ref;
101  if (mservice && mservice->hasService( port.getName()) ) {
102  // Since there is at least one child service, mservice is ref counted. The danger here is that mservice is destructed during removeService()
103  // for this reason, we take a ref to mservice until we leave addPort.
104  mservice_ref = mservice->provides(); // uses shared_from_this()
105  log(Warning) <<"'addPort' "<< port.getName() << ": name already in use as Service. Replacing previous service with new one." <<endlog();
106  mservice->removeService(port.getName());
107  }
108 
109  if (!mservice) {
110  log(Warning) <<"'addPort' "<< port.getName() << ": DataFlowInterface not given to parent. Not adding Service." <<endlog();
111  return port;
112  }
113  Service::shared_ptr ms( this->createPortObject( port.getName()) );
114  if ( ms )
115  mservice->addService( ms );
116  return port;
117  }
118 
119 #ifdef ORO_SIGNALLING_PORTS
120  void DataFlowInterface::setupHandles() {
121  for_each(handles.begin(), handles.end(), boost::bind(&Handle::connect, _1));
122  }
123 
124  void DataFlowInterface::cleanupHandles() {
125  for_each(handles.begin(), handles.end(), boost::bind(&Handle::disconnect, _1));
126  }
127 #else
129  {
130  if ( mservice && mservice->getOwner() )
131  mservice->getOwner()->dataOnPort(port);
132  }
133 #endif
134 
136  this->addLocalPort(port);
137 
138  if (mservice == 0 || mservice->getOwner() == 0) {
139  log(Error) << "addLocalEventPort "<< port.getName() <<": DataFlowInterface not part of a TaskContext. Will not trigger any TaskContext nor register callback." <<endlog();
140  return port;
141  }
142 
143 #ifdef ORO_SIGNALLING_PORTS
144  // setup synchronous callback, only purpose is to register that port fired and trigger the TC's engine.
145  Handle h = port.getNewDataOnPortEvent()->connect(boost::bind(&TaskContext::dataOnPort, mservice->getOwner(), _1) );
146  if (h) {
147  log(Info) << mservice->getName() << " will be triggered when new data is available on InputPort " << port.getName() << endlog();
148  handles.push_back(h);
149  } else {
150  log(Error) << mservice->getName() << " can't connect to event of InputPort " << port.getName() << endlog();
151  return port;
152  }
153 #endif
154  if (callback)
155  mservice->getOwner()->dataOnPortCallback(&port,callback); // the handle will be deleted when the port is removed.
156 
157 #ifndef ORO_SIGNALLING_PORTS
158  port.signalInterface(true);
159 #endif
160  return port;
161  }
162 
163  void DataFlowInterface::removePort(const std::string& name) {
164  for ( Ports::iterator it(mports.begin());
165  it != mports.end();
166  ++it)
167  if ( (*it)->getName() == name ) {
168  Service::shared_ptr mservice_ref;
169  if (mservice && mservice->hasService(name) ) {
170  // Since there is at least one child service, mservice is ref counted. The danger here is that mservice is destructed during removeService()
171  // for this reason, we take a ref to mservice until we leave removePort.
172  mservice_ref = mservice->provides(); // uses shared_from_this()
173  mservice->removeService( name );
174  if (mservice->getOwner())
175  mservice->getOwner()->dataOnPortRemoved( *it );
176  }
177  (*it)->disconnect(); // remove all connections and callbacks.
178  (*it)->setInterface(0);
179  mports.erase(it);
180  return;
181  }
182  }
183 
184  void DataFlowInterface::removeLocalPort(const std::string& name) {
185  for ( Ports::iterator it(mports.begin());
186  it != mports.end();
187  ++it)
188  if ( (*it)->getName() == name ) {
189  (*it)->disconnect(); // remove all connections and callbacks.
190  (*it)->setInterface(0);
191  mports.erase(it);
192  return;
193  }
194  }
195 
197  return mports;
198  }
199 
201  std::vector<std::string> res;
202  for ( Ports::const_iterator it(mports.begin());
203  it != mports.end();
204  ++it)
205  res.push_back( (*it)->getName() );
206  return res;
207  }
208 
209  PortInterface* DataFlowInterface::getPort(const std::string& name) const {
210  for ( Ports::const_iterator it(mports.begin());
211  it != mports.end();
212  ++it)
213  if ( (*it)->getName() == name )
214  return *it;
215  return 0;
216  }
217 
218  std::string DataFlowInterface::getPortDescription(const std::string& name) const {
219  for ( Ports::const_iterator it(mports.begin());
220  it != mports.end();
221  ++it)
222  if ( (*it)->getName() == name )
223  return (*it)->getDescription();
224  return "";
225  }
226 
227  bool DataFlowInterface::setPortDescription(const std::string& name, const std::string description) {
229  if (srv) {
230  srv->doc(description);
231  return true;
232  }
233  return false;
234  }
235 
236  Service* DataFlowInterface::createPortObject(const std::string& name) {
237  PortInterface* p = this->getPort(name);
238  if ( !p )
239  return 0;
240  Service* to = p->createPortObject();
241  if (to) {
242  std::string d = this->getPortDescription(name);
243  if ( !d.empty() )
244  to->doc( d );
245  else
246  to->doc("No description set for this Port. Use .doc() to document it.");
247  }
248  return to;
249  }
250 
252  {
253  // remove TaskObjects:
254  for ( Ports::iterator it(mports.begin());
255  it != mports.end();
256  ++it) {
257  if (mservice)
258  mservice->removeService( (*it)->getName() );
259  }
260  mports.clear();
261  }
262 
263  bool DataFlowInterface::chkPtr(const std::string & where, const std::string & name, const void *ptr)
264  {
265  if ( ptr == 0) {
266  log(Error) << "You tried to add a null pointer in '"<< where << "' for the object '" << name << "'. Fix your code !"<< endlog();
267  return false;
268  }
269  return true;
270  }
271 
272 }
const std::string & getName() const
Returns the name of this service instance.
Definition: Service.hpp:139
The base class of the InputPort.
base::PortInterface & addPort(const std::string &name, base::PortInterface &port)
Name and add a Port to the interface of this task and add a Service with the same name of the port...
void removeLocalPort(const std::string &name)
Remove a locally added Port from this interface.
TaskContext * getOwner() const
The owner is the top-level TaskContext owning this service (indirectly).
Definition: Service.hpp:185
Service::shared_ptr provides()
Returns this Service, unless no shared_ptr yet exists.
Definition: Service.cpp:112
PortNames getPortNames() const
Get all port names of this interface.
virtual void removeService(std::string const &service_name)
Remove a previously added sub-service, potentially freeing it (and this) from memory.
Definition: Service.cpp:103
base::PortInterface & addLocalPort(base::PortInterface &port)
Add a Port to this task without registering a service for it.
const std::string & getName() const
Get the name of this Port.
shared_ptr getService(const std::string &service_name)
Returns a shared pointer to strictly a sub-service of a null pointer if !hasService(service_name).
Definition: Service.cpp:142
void signalInterface(bool true_false)
When called with true, will signal the DataFlowInterface when new data is available.
std::string getPortDescription(const std::string &name) const
Get the description of an added Port.
base::InputPortInterface & addEventPort(const std::string &name, base::InputPortInterface &port, SlotFunction callback=SlotFunction())
Name and add an Event triggering Port to the interface of this task and add a Service with the same n...
Ports mports
All our ports.
base::InputPortInterface & addLocalEventPort(base::InputPortInterface &port, SlotFunction callback=SlotFunction())
Add an Event triggering Port to this task without registering a service for it.
boost::shared_ptr< Service > shared_ptr
Definition: Service.hpp:101
This class allows storage and retrieval of operations, ports, attributes and properties provided by a...
Definition: Service.hpp:93
bool disconnect()
Disconnect the slot from the signal.
Definition: Handle.cpp:72
base::PortInterface * getPort(const std::string &name) const
Get an added port.
void removePort(const std::string &name)
Remove a Port from this interface.
virtual Service * createPortObject()
Create accessor Object for this Port, for addition to a TaskContext Object interface.
const std::string & doc() const
Returns a descriptive text for this service.
Definition: Service.hpp:144
virtual bool addService(shared_ptr obj)
Add a new sub-service to this Service.
Definition: Service.cpp:81
bool connect()
(Re-)Connect the slot with the signal.
Definition: Handle.cpp:65
boost::function< void(base::PortInterface *)> SlotFunction
bool hasService(const std::string &service_name)
Check if this service has the sub-service service_name.
Definition: Service.cpp:179
std::vector< base::PortInterface * > Ports
A sequence of pointers to ports.
bool setPortDescription(const std::string &name, const std::string description)
Sets the description for the service of an added port.
std::vector< std::string > PortNames
A sequence of names of ports.
void setInterface(DataFlowInterface *iface)
Once a port is added to a DataFlowInterface, it gets a pointer to that interface. ...
bool chkPtr(const std::string &where, const std::string &name, const void *ptr)
The TaskContext is the C++ representation of an Orocos component.
Definition: TaskContext.hpp:93
Ports getPorts() const
Get all ports of this interface.
Service * mservice
The parent Service.
void dataOnPort(base::PortInterface *port)
Used by the input ports to notify this class of new data.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:51
void clear()
Remove all added ports from this interface and all associated TaskObjects.
The base class of every data flow port.
DataFlowInterface(Service *parent=0)
Construct the DataFlow interface of a Service.
The Handle holds the information, and allows manipulation, of a connection between a internal::Signal...
Definition: Handle.hpp:66
TaskContext * getOwner() const
Returns the component this interface belongs to.
Service * createPortObject(const std::string &name)
Create a Service through which one can access a Port.