Orocos Real-Time Toolkit  2.9.0
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()->setDataOnPortCallback(&port,callback); // the handle will be deleted when the port is removed.
156  else
157  mservice->getOwner()->setDataOnPortCallback(&port,boost::bind(&TaskCore::trigger, mservice->getOwner()) ); // default schedules an updateHook()
158 
159 #ifndef ORO_SIGNALLING_PORTS
160  port.signalInterface(true);
161 #endif
162  return port;
163  }
164 
165  void DataFlowInterface::removePort(const std::string& name) {
166  for ( Ports::iterator it(mports.begin());
167  it != mports.end();
168  ++it)
169  if ( (*it)->getName() == name ) {
170  (*it)->disconnect(); // remove all connections and callbacks.
171  Service::shared_ptr mservice_ref;
172  if (mservice && mservice->hasService(name) ) {
173  // Since there is at least one child service, mservice is ref counted. The danger here is that mservice is destructed during removeService()
174  // for this reason, we take a ref to mservice until we leave removePort.
175  mservice_ref = mservice->provides(); // uses shared_from_this()
176  mservice->removeService( name );
177  if (mservice->getOwner())
178  mservice->getOwner()->removeDataOnPortCallback( *it );
179  }
180  (*it)->setInterface(0);
181  mports.erase(it);
182  return;
183  }
184  }
185 
186  void DataFlowInterface::removeLocalPort(const std::string& name) {
187  for ( Ports::iterator it(mports.begin());
188  it != mports.end();
189  ++it)
190  if ( (*it)->getName() == name ) {
191  (*it)->disconnect(); // remove all connections and callbacks.
192  (*it)->setInterface(0);
193  mports.erase(it);
194  return;
195  }
196  }
197 
199  return mports;
200  }
201 
203  std::vector<std::string> res;
204  for ( Ports::const_iterator it(mports.begin());
205  it != mports.end();
206  ++it)
207  res.push_back( (*it)->getName() );
208  return res;
209  }
210 
211  PortInterface* DataFlowInterface::getPort(const std::string& name) const {
212  for ( Ports::const_iterator it(mports.begin());
213  it != mports.end();
214  ++it)
215  if ( (*it)->getName() == name )
216  return *it;
217  return 0;
218  }
219 
220  std::string DataFlowInterface::getPortDescription(const std::string& name) const {
221  for ( Ports::const_iterator it(mports.begin());
222  it != mports.end();
223  ++it)
224  if ( (*it)->getName() == name )
225  return (*it)->getDescription();
226  return "";
227  }
228 
229  bool DataFlowInterface::setPortDescription(const std::string& name, const std::string description) {
231  if (srv) {
232  srv->doc(description);
233  return true;
234  }
235  return false;
236  }
237 
238  Service* DataFlowInterface::createPortObject(const std::string& name) {
239  PortInterface* p = this->getPort(name);
240  if ( !p )
241  return 0;
242  Service* to = p->createPortObject();
243  if (to) {
244  std::string d = this->getPortDescription(name);
245  if ( !d.empty() )
246  to->doc( d );
247  else
248  to->doc("No description set for this Port. Use .doc() to document it.");
249  }
250  return to;
251  }
252 
254  {
255  // remove TaskObjects:
256  for ( Ports::iterator it(mports.begin());
257  it != mports.end();
258  ++it) {
259  if (mservice)
260  mservice->removeService( (*it)->getName() );
261  }
262  mports.clear();
263  }
264 
265  bool DataFlowInterface::chkPtr(const std::string & where, const std::string & name, const void *ptr)
266  {
267  if ( ptr == 0) {
268  log(Error) << "You tried to add a null pointer in '"<< where << "' for the object '" << name << "'. Fix your code !"<< endlog();
269  return false;
270  }
271  return true;
272  }
273 
274 }
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:113
virtual bool trigger()
Invoke this method to trigger the thread of this TaskContext to execute its ExecutionEngine and the u...
Definition: TaskCore.cpp:88
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:133
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:172
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:52
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.