OrocosComponentLibrary  2.8.3
ReportingComponent.cpp
1 /***************************************************************************
2  tag: Peter Soetens Mon May 10 19:10:38 CEST 2004 ReportingComponent.cxx
3 
4  ReportingComponent.cxx - description
5  -------------------
6  begin : Mon May 10 2004
7  copyright : (C) 2004 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2.1 of the License, or (at your option) any later version. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19  * Lesser General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU Lesser General Public *
22  * License along with this library; if not, write to the Free Software *
23  * Foundation, Inc., 59 Temple Place, *
24  * Suite 330, Boston, MA 02111-1307 USA *
25  * *
26  ***************************************************************************/
27 
28 #include "ReportingComponent.hpp"
29 #include <rtt/Logger.hpp>
30 
31 // Impl.
32 #include "EmptyMarshaller.hpp"
33 #include <rtt/marsh/PropertyDemarshaller.hpp>
34 #include <rtt/marsh/PropertyMarshaller.hpp>
35 #include <iostream>
36 #include <fstream>
37 #include <exception>
38 #include <boost/algorithm/string.hpp>
39 
40 #include "ocl/Component.hpp"
41 #include <rtt/types/PropertyDecomposition.hpp>
42 #include <boost/lexical_cast.hpp>
43 
44 ORO_CREATE_COMPONENT_TYPE()
45 
46 
47 namespace OCL
48 {
49  using namespace std;
50  using namespace RTT;
51  using namespace RTT::detail;
52 
55  class CheckSizeDataSource : public ValueDataSource<bool>
56  {
57  mutable int msize;
58  DataSource<int>::shared_ptr mds;
59  DataSource<bool>::shared_ptr mupstream;
60  public:
61  CheckSizeDataSource(int size, DataSource<int>::shared_ptr ds, DataSource<bool>::shared_ptr upstream)
62  : msize(size), mds(ds), mupstream(upstream)
63  {}
67  bool get() const{
68  // it's very important to first check upstream, because
69  // if upstream changed size, downstream might already be corrupt !
70  // (downstream will be corrupt upon capacity changes upstream)
71  bool result = true;
72  if (mupstream)
73  result = (mupstream->get() && msize == mds->get());
74  else
75  result = (msize == mds->get());
76  msize = mds->get();
77  return result;
78  }
79  };
80 
87  bool memberDecomposition( base::DataSourceBase::shared_ptr dsb, PropertyBag& targetbag, DataSource<bool>::shared_ptr& resized)
88  {
89  assert(dsb);
90 
91  vector<string> parts = dsb->getMemberNames();
92  if ( parts.empty() ) {
93  return false;
94  }
95 
96  targetbag.setType( dsb->getTypeName() );
97 
98  // needed for recursion.
99  auto_ptr< Property<PropertyBag> > recurse_bag( new Property<PropertyBag>("recurse_bag","") );
100  // First at the explicitly listed parts:
101  for(vector<string>::iterator it = parts.begin(); it != parts.end(); ++it ) {
102  // we first force getMember to get to the type, then we do it again but with a reference set.
103  DataSourceBase::shared_ptr part = dsb->getMember( *it );
104  if (!part) {
105  log(Error) <<"memberDecomposition: Inconsistent type info for "<< dsb->getTypeName() << ": reported to have part '"<<*it<<"' but failed to return it."<<endlog();
106  continue;
107  }
108  if ( !part->isAssignable() ) {
109  // For example: the case for size() and capacity() in SequenceTypeInfo
110  log(Debug)<<"memberDecomposition: Part "<< *it << ":"<< part->getTypeName() << " is not changeable."<<endlog();
111  continue;
112  }
113  // now the reference magic:
114  DataSourceBase::shared_ptr ref = part->getTypeInfo()->buildReference( 0 );
115  dsb->getTypeInfo()->getMember( dynamic_cast<Reference*>(ref.get() ), dsb, *it); // fills in ref
116  // newpb will contain a reference to the port's datasource data !
117  PropertyBase* newpb = part->getTypeInfo()->buildProperty(*it,"Part", ref);
118  if ( !newpb ) {
119  log(Error)<< "Decomposition failed because Part '"<<*it<<"' is not known to type system."<<endlog();
120  continue;
121  }
122  // finally recurse or add it to the target bag:
123  if ( !memberDecomposition( ref, recurse_bag->value(), resized) ) {
124  assert( recurse_bag->value().empty() );
125  // finally: check for conversions (enums use this):
126  base::DataSourceBase::shared_ptr converted = newpb->getTypeInfo()->convertType( dsb );
127  if ( converted && converted != dsb ) {
128  // converted contains another type.
129  targetbag.add( converted->getTypeInfo()->buildProperty(*it, "", converted) );
130  delete newpb;
131  } else
132  targetbag.ownProperty( newpb ); // leaf
133  } else {
134  recurse_bag->setName(*it);
135  // setType() is done by recursive of self.
136  targetbag.ownProperty( recurse_bag.release() ); //recursed.
137  recurse_bag.reset( new Property<PropertyBag>("recurse_bag","") );
138  delete newpb; // since we recursed, the recurse_bag now 'embodies' newpb.
139  }
140  }
141 
142  // Next get the numbered parts. This is much more involved since sequences may be resizable.
143  // We keep track of the size, and if that changes, we will have to force a re-decomposition
144  // of the sequence's internals.
145  DataSource<int>::shared_ptr size = DataSource<int>::narrow( dsb->getMember("size").get() );
146  if (size) {
147  int msize = size->get();
148  for (int i=0; i < msize; ++i) {
149  string indx = boost::lexical_cast<string>( i );
150  DataSourceBase::shared_ptr item = dsb->getMember(indx);
151  resized = new CheckSizeDataSource( msize, size, resized );
152  if (item) {
153  if ( !item->isAssignable() ) {
154  // For example: the case for size() and capacity() in SequenceTypeInfo
155  log(Warning)<<"memberDecomposition: Item '"<< indx << "' of type "<< dsb->getTypeName() << " is not changeable."<<endlog();
156  continue;
157  }
158  // finally recurse or add it to the target bag:
159  PropertyBase* newpb = item->getTypeInfo()->buildProperty( indx,"",item);
160  if ( !memberDecomposition( item, recurse_bag->value(), resized) ) {
161  targetbag.ownProperty( newpb ); // leaf
162  } else {
163  delete newpb;
164  recurse_bag->setName( indx );
165  // setType() is done by recursive of self.
166  targetbag.ownProperty( recurse_bag.release() ); //recursed.
167  recurse_bag.reset( new Property<PropertyBag>("recurse_bag","") );
168  }
169  }
170  }
171  }
172  if (targetbag.empty() )
173  log(Debug) << "memberDecomposition: "<< dsb->getTypeName() << " returns an empty property bag." << endlog();
174  return true;
175  }
176 
177  ReportingComponent::ReportingComponent( std::string name /*= "Reporting" */ )
178  : TaskContext( name ),
179  report("Report"), snapshotted(false),
180  writeHeader("WriteHeader","Set to true to start each report with a header.", true),
181  decompose("Decompose","Set to false in order to not decompose the port data. The marshaller must be able to handle this itself for this to work.", true),
182  insnapshot("Snapshot","Set to true to enable snapshot mode. This will cause a non-periodic reporter to only report data upon the snapshot() operation.",false),
183  synchronize_with_logging("Synchronize","Set to true if the timestamp should be synchronized with the logging",false),
184  report_data("ReportData","A PropertyBag which defines which ports or components to report."),
185  report_policy( ConnPolicy::data(ConnPolicy::LOCK_FREE,true,false) ),
186  onlyNewData(false),
187  starttime(0),
188  timestamp("TimeStamp","The time at which the data was read.",0.0)
189  {
190  this->provides()->doc("Captures data on data ports. A periodic reporter will sample each added port according to its period, a non-periodic reporter will write out data as it comes in, or only during a snapshot() if the Snapshot property is true.");
191 
192  this->properties()->addProperty( writeHeader );
193  this->properties()->addProperty( decompose );
194  this->properties()->addProperty( insnapshot );
195  this->properties()->addProperty( synchronize_with_logging);
196  this->properties()->addProperty( report_data);
197  this->properties()->addProperty( "ReportPolicy", report_policy).doc("The ConnPolicy for the reporter's port connections.");
198  this->properties()->addProperty( "ReportOnlyNewData", onlyNewData).doc("Turn on in order to only write out NewData on ports and omit unchanged ports. Turn off in order to sample and write out all ports (even old data).");
199  // Add the methods, methods make sure that they are
200  // executed in the context of the (non realtime) caller.
201 
202  this->addOperation("snapshot", &ReportingComponent::snapshot , this, RTT::OwnThread).doc("Take a new shapshot of all data and cause them to be written out.");
203  this->addOperation("screenComponent", &ReportingComponent::screenComponent , this, RTT::ClientThread).doc("Display the variables and ports of a Component.").arg("Component", "Name of the Component");
204  this->addOperation("reportComponent", &ReportingComponent::reportComponent , this, RTT::ClientThread).doc("Add a peer Component and report all its data ports").arg("Component", "Name of the Component");
205  this->addOperation("unreportComponent", &ReportingComponent::unreportComponent , this, RTT::ClientThread).doc("Remove all Component's data ports from reporting.").arg("Component", "Name of the Component");
206  this->addOperation("reportData", &ReportingComponent::reportData , this, RTT::ClientThread).doc("Add a Component's Property or attribute for reporting.").arg("Component", "Name of the Component").arg("Data", "Name of the Data to report. A property's or attribute's name.");
207  this->addOperation("unreportData", &ReportingComponent::unreportData , this, RTT::ClientThread).doc("Remove a Data object from reporting.").arg("Component", "Name of the Component").arg("Data", "Name of the property or attribute.");
208  this->addOperation("reportPort", &ReportingComponent::reportPort , this, RTT::ClientThread).doc("Add a Component's OutputPort for reporting.").arg("Component", "Name of the Component").arg("Port", "Name of the Port.");
209  this->addOperation("unreportPort", &ReportingComponent::unreportPort , this, RTT::ClientThread).doc("Remove a Port from reporting.").arg("Component", "Name of the Component").arg("Port", "Name of the Port.");
210 
211  }
212 
213  ReportingComponent::~ReportingComponent() {}
214 
215 
216  bool ReportingComponent::addMarshaller( marsh::MarshallInterface* headerM, marsh::MarshallInterface* bodyM)
217  {
218  boost::shared_ptr<marsh::MarshallInterface> header(headerM);
219  boost::shared_ptr<marsh::MarshallInterface> body(bodyM);
220  if ( !header && !body)
221  return false;
222  if ( !header )
223  header.reset( new EmptyMarshaller() );
224  if ( !body)
225  body.reset( new EmptyMarshaller());
226 
227  marshallers.push_back( std::make_pair( header, body ) );
228  return true;
229  }
230 
232  {
233  marshallers.clear();
234  return true;
235  }
236 
238  {
239  root.clear(); // uses shared_ptr.
240  deletePropertyBag( report );
241  }
242 
244  {
245  Logger::In in("ReportingComponent");
246 
247  // we make a copy to be allowed to iterate over and exted report_data:
248  PropertyBag bag = report_data.value();
249 
250  if ( bag.empty() ) {
251  log(Error) <<"No port or component configuration loaded."<<endlog();
252  log(Error) <<"Please use marshalling.loadProperties(), reportComponent() (scripting) or LoadProperties (XML) in order to fill in ReportData." <<endlog();
253  return false;
254  }
255 
256  bool ok = true;
257  PropertyBag::const_iterator it = bag.getProperties().begin();
258  while ( it != bag.getProperties().end() )
259  {
260  Property<std::string>* compName = dynamic_cast<Property<std::string>* >( *it );
261  if ( !compName )
262  log(Error) << "Expected Property \""
263  << (*it)->getName() <<"\" to be of type string."<< endlog();
264  else if ( compName->getName() == "Component" ) {
265  std::string name = compName->value(); // we will delete this property !
266  this->unreportComponent( name );
267  ok &= this->reportComponent( name );
268  }
269  else if ( compName->getName() == "Port" ) {
270  string cname = compName->value().substr(0, compName->value().find("."));
271  string pname = compName->value().substr( compName->value().find(".")+1, string::npos);
272  if (cname.empty() || pname.empty() ) {
273  log(Error) << "The Port value '"<<compName->getName()<< "' must at least consist of a component name followed by a dot and the port name." <<endlog();
274  ok = false;
275  continue;
276  }
277  this->unreportPort(cname,pname);
278  ok &= this->reportPort(cname, pname);
279  }
280  else if ( compName->getName() == "Data" ) {
281  string cname = compName->value().substr(0, compName->value().find("."));
282  string pname = compName->value().substr( compName->value().find(".")+1, string::npos);
283  if (cname.empty() || pname.empty() ) {
284  log(Error) << "The Data value '"<<compName->getName()<< "' must at least consist of a component name followed by a dot and the property/attribute name." <<endlog();
285  ok = false;
286  continue;
287  }
288  this->unreportData(cname,pname);
289  ok &= this->reportData(cname, pname);
290  }
291  else {
292  log(Error) << "Expected \"Component\", \"Port\" or \"Data\", got "
293  << compName->getName() << endlog();
294  ok = false;
295  }
296  ++it;
297  }
298  return ok;
299  }
300 
301  bool ReportingComponent::screenComponent( const std::string& comp )
302  {
303  Logger::In in("ReportingComponent::screenComponent");
304  log(Error) << "not implemented." <<comp<<endlog();
305  return false;
306  }
307 
308  bool ReportingComponent::screenImpl( const std::string& comp, std::ostream& output)
309  {
310  Logger::In in("ReportingComponent");
311  TaskContext* c = this->getPeer(comp);
312  if ( c == 0) {
313  log(Error) << "Unknown Component: " <<comp<<endlog();
314  return false;
315  }
316  output << "Screening Component '"<< comp << "' : "<< endl << endl;
317  PropertyBag* bag = c->properties();
318  if (bag) {
319  output << "Properties :" << endl;
320  for (PropertyBag::iterator it= bag->begin(); it != bag->end(); ++it)
321  output << " " << (*it)->getName() << " : " << (*it)->getDataSource() << endl;
322  }
323  ConfigurationInterface::AttributeNames atts = c->provides()->getAttributeNames();
324  if ( !atts.empty() ) {
325  output << "Attributes :" << endl;
326  for (ConfigurationInterface::AttributeNames::iterator it= atts.begin(); it != atts.end(); ++it)
327  output << " " << *it << " : " << c->provides()->getValue(*it)->getDataSource() << endl;
328  }
329 
330  vector<string> ports = c->ports()->getPortNames();
331  if ( !ports.empty() ) {
332  output << "Ports :" << endl;
333  for (vector<string>::iterator it= ports.begin(); it != ports.end(); ++it) {
334  output << " " << *it << " : ";
335  if (c->ports()->getPort(*it)->connected() )
336  output << "(connected)" << endl;
337  else
338  output << "(not connected)" << endl;
339  }
340  }
341  return true;
342  }
343 
344  bool ReportingComponent::reportComponent( const std::string& component ) {
345  Logger::In in("ReportingComponent");
346  // Users may add own data sources, so avoid duplicates
347  //std::vector<std::string> sources = comp->data()->getNames();
348  TaskContext* comp = this->getPeer(component);
349  if ( !comp ) {
350  log(Error) << "Could not report Component " << component <<" : no such peer."<<endlog();
351  return false;
352  }
353  if ( !report_data.value().findValue<string>(component) )
354  report_data.value().ownProperty( new Property<string>("Component","",component) );
355  Ports ports = comp->ports()->getPorts();
356  for (Ports::iterator it = ports.begin(); it != ports.end() ; ++it) {
357  log(Debug) << "Checking port " << (*it)->getName()<<"."<<endlog();
358  this->reportPort( component, (*it)->getName() );
359  }
360  return true;
361  }
362 
363 
364  bool ReportingComponent::unreportComponent( const std::string& component ) {
365  TaskContext* comp = this->getPeer(component);
366  if ( !comp ) {
367  log(Error) << "Could not unreport Component " << component <<" : no such peer."<<endlog();
368  return false;
369  }
370  Ports ports = comp->ports()->getPorts();
371  for (Ports::iterator it = ports.begin(); it != ports.end() ; ++it) {
372  this->unreportDataSource( component + "." + (*it)->getName() );
373  unreportPort(component, (*it)->getName() );
374  }
375  base::PropertyBase* pb = report_data.value().findValue<string>(component);
376  if (pb)
377  report_data.value().removeProperty( pb );// pb is deleted by bag
378  return true;
379  }
380 
381  // report a specific connection.
382  bool ReportingComponent::reportPort(const std::string& component, const std::string& port ) {
383  Logger::In in("ReportingComponent");
384  TaskContext* comp = this->getPeer(component);
385  if ( this->ports()->getPort(component +"_"+port) ) {
386  log(Warning) <<"Already reporting "<<component<<"."<<port<<": removing old port first."<<endlog();
387  this->unreportPort(component,port);
388  }
389  if ( !comp ) {
390  log(Error) << "Could not report Component " << component <<" : no such peer."<<endlog();
391  return false;
392  }
393  std::vector<std::string> strs;
394  boost::split(strs, port, boost::is_any_of("."));
395 
396  // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751)
397  if (strs.empty()) return false;
398 
399  Service::shared_ptr service=comp->provides();
400  while ( strs.size() != 1 && service) {
401  service = service->getService( strs.front() );
402  if (service)
403  strs.erase( strs.begin() );
404  }
405  if (!service) {
406  log(Error) <<"No such service: '"<< strs.front() <<"' while looking for port '"<< port<<"'"<<endlog();
407  return 0;
408  }
409  base::PortInterface* porti = 0;
410  porti = service->getPort(strs.front());
411  if ( !porti ) {
412  log(Error) << "Could not report Port " << port
413  <<" : no such port on Component "<<component<<"."<<endlog();
414  return false;
415  }
416 
417  base::InputPortInterface* ipi = dynamic_cast<base::InputPortInterface*>(porti);
418  if (ipi) {
419  log(Error) << "Can not report InputPort "<< porti->getName() <<" of Component " << component <<endlog();
420  return false;
421  }
422  // create new port temporarily
423  // this port is only created with the purpose of
424  // creating a connection object.
425  base::PortInterface* ourport = porti->antiClone();
426  assert(ourport);
427  ourport->setName(component + "_" + port);
428  ipi = dynamic_cast<base::InputPortInterface*> (ourport);
429  assert(ipi);
430 
431  if (report_policy.type == ConnPolicy::DATA ) {
432  log(Info) << "Not buffering of data flow connections. You may miss samples." <<endlog();
433  } else {
434  log(Info) << "Buffering ports with size "<< report_policy.size << ", as set in ReportPolicy property." <<endlog();
435  }
436 
437  this->ports()->addEventPort( *ipi );
438  if (porti->connectTo(ourport, report_policy ) == false)
439  {
440  log(Error) << "Could not connect to OutputPort " << porti->getName() << endlog();
441  this->ports()->removePort(ourport->getName());
442  delete ourport; // XXX/TODO We're leaking ourport !
443  return false;
444  }
445 
446  if (this->reportDataSource(component + "." + port, "Port",
447  ipi->getDataSource(),ipi, true) == false)
448  {
449  log(Error) << "Failed reporting port " << port << endlog();
450  this->ports()->removePort(ourport->getName());
451  delete ourport;
452  return false;
453  }
454 
455  log(Info) << "Monitoring OutputPort " << port << " : ok." << endlog();
456  // Add port to ReportData properties if component nor port are listed yet.
457  if ( !report_data.value().findValue<string>(component) && !report_data.value().findValue<string>( component+"."+port) )
458  report_data.value().ownProperty(new Property<string>("Port","",component+"."+port));
459  return true;
460  }
461 
462  bool ReportingComponent::unreportPort(const std::string& component, const std::string& port ) {
463  base::PortInterface* ourport = this->ports()->getPort(component + "_" + port);
464  if ( this->unreportDataSource( component + "." + port ) && report_data.value().removeProperty( report_data.value().findValue<string>(component+"."+port))) {
465  this->ports()->removePort(ourport->getName());
466  delete ourport; // also deletes datasource.
467  return true;
468  }
469  return false;
470  }
471 
472  // report a specific datasource, property,...
473  bool ReportingComponent::reportData(const std::string& component,const std::string& dataname)
474  {
475  Logger::In in("ReportingComponent");
476  TaskContext* comp = this->getPeer(component);
477  if ( !comp ) {
478  log(Error) << "Could not report Component " << component <<" : no such peer."<<endlog();
479  return false;
480  }
481  // Is it an attribute ?
482  if ( comp->provides()->getValue( dataname ) ) {
483  if (this->reportDataSource( component + "." + dataname, "Data",
484  comp->provides()->getValue( dataname )->getDataSource(), 0, false ) == false) {
485  log(Error) << "Failed reporting data " << dataname <<endlog();
486  return false;
487  }
488  }
489 
490  // Is it a property ?
491  if ( comp->properties() && comp->properties()->find( dataname ) ) {
492  if (this->reportDataSource( component + "." + dataname, "Data",
493  comp->properties()->find( dataname )->getDataSource(), 0, false ) == false) {
494  log(Error) << "Failed reporting data " << dataname <<endlog();
495  return false;
496  }
497  }
498  // Ok. we passed.
499  // Add port to ReportData properties if data not listed yet.
500  if ( !report_data.value().findValue<string>( component+"."+dataname) )
501  report_data.value().ownProperty(new Property<string>("Data","",component+"."+dataname));
502  return true;
503  }
504 
505  bool ReportingComponent::unreportData(const std::string& component,const std::string& datasource) {
506  return this->unreportDataSource( component +"." + datasource) && report_data.value().removeProperty( report_data.value().findValue<string>(component+"."+datasource));
507  }
508 
509  bool ReportingComponent::reportDataSource(std::string tag, std::string type, base::DataSourceBase::shared_ptr orig, base::InputPortInterface* ipi, bool track)
510  {
511  // check for duplicates:
512  for (Reports::iterator it = root.begin();
513  it != root.end(); ++it)
514  if ( it->get<T_QualName>() == tag ) {
515  return true;
516  }
517 
518  // creates a copy of the data and an update command to
519  // update the copy from the original.
520  base::DataSourceBase::shared_ptr clone = orig->getTypeInfo()->buildValue();
521  if ( !clone ) {
522  log(Error) << "Could not report '"<< tag <<"' : unknown type." << endlog();
523  return false;
524  }
525  PropertyBase* prop = 0;
526  root.push_back( boost::make_tuple( tag, orig, type, prop, ipi, false, track ) );
527  return true;
528  }
529 
530  bool ReportingComponent::unreportDataSource(std::string tag)
531  {
532  for (Reports::iterator it = root.begin();
533  it != root.end(); ++it)
534  if ( it->get<T_QualName>() == tag ) {
535  root.erase(it);
536  return true;
537  }
538  return false;
539  }
540 
541  bool ReportingComponent::startHook() {
542  Logger::In in("ReportingComponent");
543  if (marshallers.begin() == marshallers.end()) {
544  log(Error) << "Need at least one marshaller to write reports." <<endlog();
545  return false;
546  }
547 
548  if(synchronize_with_logging.get())
549  starttime = Logger::Instance()->getReferenceTime();
550  else
551  starttime = os::TimeService::Instance()->getTicks();
552 
553  // Get initial data samples
554  this->copydata();
555  this->makeReport2();
556 
557  // write headers
558  if (writeHeader.get()) {
559  // call all header marshallers.
560  for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
561  it->first->serialize( report );
562  it->first->flush();
563  }
564  }
565 
566  // write initial values with all value marshallers (uses the forcing above)
567  if ( getActivity()->isPeriodic() ) {
568  for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
569  it->second->serialize( report );
570  it->second->flush();
571  }
572  }
573 
574  // Turn off port triggering in snapshot mode, and vice versa.
575  // Also clears any old data in the buffers
576  for(Reports::iterator it = root.begin(); it != root.end(); ++it )
577  if ( it->get<T_Port>() ) {
578 #ifndef ORO_SIGNALLING_PORTS
579  it->get<T_Port>()->signalInterface( !insnapshot.get() );
580 #endif
581  it->get<T_Port>()->clear();
582  }
583 
584 
585  snapshotted = false;
586  return true;
587  }
588 
590  // this function always copies and reports all data It's run in ownthread, so updateHook will be run later.
591  if ( getActivity()->isPeriodic() )
592  return;
593  snapshotted = true;
594  updateHook();
595  }
596 
598  timestamp = os::TimeService::Instance()->secondsSince( starttime );
599 
600  // result will become true if more data is to be read.
601  bool result = false;
602  // This evaluates the InputPortDataSource evaluate() returns true upon new data.
603  for(Reports::iterator it = root.begin(); it != root.end(); ++it ) {
604  it->get<T_NewData>() = (it->get<T_PortDS>())->evaluate(); // stores 'NewData' flag.
605  // if its a property/attr, get<T_NewData> will always be true, so we override (clear) with get<T_Tracked>.
606  result = result || ( it->get<T_NewData>() && it->get<T_Tracked>() );
607  }
608  return result;
609  }
610 
611  void ReportingComponent::makeReport2()
612  {
613  // Uses the port DS itself to make the report.
614  assert( report.empty() );
615  // For the timestamp, we need to add a new property object:
616  report.add( timestamp.getTypeInfo()->buildProperty( timestamp.getName(), "", timestamp.getDataSource() ) );
617  DataSource<bool>::shared_ptr checker;
618  for(Reports::iterator it = root.begin(); it != root.end(); ++it ) {
619  Property<PropertyBag>* subbag = new Property<PropertyBag>( it->get<T_QualName>(), "");
620  if ( decompose.get() && memberDecomposition( it->get<T_PortDS>(), subbag->value(), checker ) ) {
621  report.add( subbag );
622  it->get<T_Property>() = subbag;
623  } else {
624  // property or simple value port...
625  base::DataSourceBase::shared_ptr converted = it->get<T_PortDS>()->getTypeInfo()->convertType( it->get<T_PortDS>() );
626  if ( converted && converted != it->get<T_PortDS>() ) {
627  // converted contains another type.
628  PropertyBase* convProp = converted->getTypeInfo()->buildProperty(it->get<T_QualName>(), "", converted);
629  it->get<T_Property>() = convProp;
630  report.add(convProp);
631  } else {
632  PropertyBase* origProp = it->get<T_PortDS>()->getTypeInfo()->buildProperty(it->get<T_QualName>(), "", it->get<T_PortDS>());
633  it->get<T_Property>() = origProp;
634  report.add(origProp);
635  }
636  delete subbag;
637  }
638 
639  }
640  mchecker = checker;
641  }
642 
644  {
645  // Only clones were added to result, so delete them.
646  deletePropertyBag( report );
647  }
648 
650  //If not periodic and insnapshot is true, only continue if snapshot is called.
651  if( !getActivity()->isPeriodic() && insnapshot.get() && !snapshotted)
652  return;
653  else
654  snapshotted = false;
655 
656  // if any data sequence got resized, we rebuild the whole bunch.
657  // otherwise, we need to track every individual array (not impossible though, but still needs an upstream concept).
658  if ( mchecker && mchecker->get() == false ) {
659  cleanReport();
660  makeReport2();
661  } else
662  copydata();
663 
664  do {
665  // Step 3: print out the result
666  // write out to all marshallers
667  for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
668  if ( onlyNewData ) {
669  // Serialize only changed ports:
670  it->second->serialize( *report.begin() ); // TimeStamp.
671  for (Reports::const_iterator i = root.begin();
672  i != root.end();
673  i++ )
674  {
675  if ( i->get<T_NewData>() )
676  it->second->serialize( i->get<T_Property>() );
677  }
678  } else {
679  // pass on all ports to the marshaller
680  it->second->serialize( report );
681  }
682  it->second->flush();
683  }
684  } while( !getActivity()->isPeriodic() && !insnapshot.get() && copydata() ); // repeat if necessary. In periodic mode we always only sample once.
685  }
686 
687  void ReportingComponent::stopHook() {
688  // tell body marshallers that serialization is done.
689  for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
690  it->second->flush();
691  }
692  cleanReport();
693  }
694 
695 }
bool snapshotted
Used to communicate between snapshot() and updateHook() if updateHook needs to make a copy...
virtual bool configureHook()
Implementation of base::TaskCore::configureHook().
void cleanReport()
Implementation of base::TaskCore::configureHook().
Helper data source to check if two sizes are still equal and check an upstream comparison as well...
bool addMarshaller(RTT::marsh::MarshallInterface *headerM, RTT::marsh::MarshallInterface *bodyM)
Adds a Plugin to receive incomming data.
STL namespace.
bool unreportPort(const std::string &component, const std::string &port)
Unreport a specific data port of a component.
virtual void updateHook()
This not real-time function processes the copied data.
A Dummy Empty MarshallInterface.
RTT::internal::DataSource< bool >::shared_ptr mchecker
If false, a sequence size has changed.
void snapshot()
Copy the reported data and trigger the generation of a sampling line.
This file contains the macros and definitions to create dynamically loadable components.
bool removeMarshallers()
Remove and delete all added Marshallers.
The Orocos Component Library.
Definition: Component.hpp:43
virtual bool screenComponent(const std::string &comp)
Write state information of a component.
bool reportPort(const std::string &component, const std::string &port)
Report a specific data port of a component.
bool unreportData(const std::string &component, const std::string &datasource)
Unreport a specific data source of a component.
bool reportComponent(const std::string &component)
Report all the data ports of a component.
bool screenImpl(const std::string &comp, std::ostream &output)
This method writes out the status of a component&#39;s interface.
bool unreportComponent(const std::string &component)
Unreport the data ports of a component.
bool memberDecomposition(base::DataSourceBase::shared_ptr dsb, PropertyBag &targetbag, DataSource< bool >::shared_ptr &resized)
Decompose a given type using getMember() into a property tree.
Definition: Category.hpp:10
bool copydata()
This real-time function makes copies of the data to be reported.
bool reportData(const std::string &component, const std::string &dataname)
Report a specific data source of a component.
virtual void cleanupHook()
Implementation of base::TaskCore::cleanupHook().