YARP
Yet Another Robot Platform
RFModule.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 #include <yarp/os/RFModule.h>
11 
12 #include <yarp/os/Bottle.h>
14 #include <yarp/os/Network.h>
15 #include <yarp/os/Os.h>
16 #include <yarp/os/Thread.h>
17 #include <yarp/os/Time.h>
18 #include <yarp/os/Vocab.h>
22 #include <yarp/os/impl/Terminal.h>
23 
24 #include <cstdio>
25 #include <cstdlib>
26 #include <string>
27 
28 using namespace yarp::os;
29 using namespace yarp::os::impl;
30 
31 namespace {
32 YARP_OS_LOG_COMPONENT(RFMODULE, "yarp.os.RFModule")
33 }
34 
36  public yarp::os::PortReader,
37  public yarp::os::Thread
38 {
39 private:
40  RFModule& owner;
41  bool attachedToPort;
42  bool attachedTerminal;
43 
44 public:
51  bool read(yarp::os::ConnectionReader& connection) override;
52 
53 
55  owner(owner),
56  attachedToPort(false),
57  attachedTerminal(false)
58  {
59  }
60 
61 
62  void run() override
63  {
64  yCInfo(RFMODULE, "Listening to terminal (type \"quit\" to stop module).");
65  bool isEof = false;
66  while (!(isEof || isStopping() || owner.isStopping())) {
67  std::string str = yarp::os::impl::Terminal::readString(&isEof);
68  if (!isEof) {
69  Bottle cmd(str);
70  Bottle reply;
71  bool ok = owner.safeRespond(cmd, reply);
72  if (ok) {
73  yCDebug(RFMODULE, "ALL: %s\n", reply.toString().c_str());
74  yCDebug(RFMODULE, "ITEM 1: %s\n", reply.get(0).toString().c_str());
75  if (reply.get(0).toString() == "help") {
76  for (size_t i = 0; i < reply.size(); i++) {
77  yCInfo(RFMODULE, "%s.", reply.get(i).toString().c_str());
78  }
79  } else {
80  yCInfo(RFMODULE, "%s.", reply.toString().c_str());
81  }
82  } else {
83  yCInfo(RFMODULE, "Command not understood -- %s.", str.c_str());
84  }
85  }
86  }
87  yCDebug(RFMODULE, "terminal shutting down\n");
88  //owner.interruptModule();
89  }
90 
91 
92  bool attach(yarp::os::Port& source)
93  {
94  attachedToPort = true;
95  source.setReader(*this);
96  return true;
97  }
98 
99 
101  {
102  attachedToPort = true;
103  source.setReader(*this);
104  return true;
105  }
106 
107 
109  {
110  attachedTerminal = true;
111 
112  Thread::start();
113  return true;
114  }
115 
116 
118  {
119  return attachedTerminal;
120  }
121 
122 
124  {
125  yCWarning(RFMODULE, "Critical: stopping thread, this might hang.");
126  Thread::stop();
127  yCWarning(RFMODULE, "done!");
128  return true;
129  }
130 };
131 
133 {
134  Bottle cmd;
135  Bottle response;
136  if (!cmd.read(connection)) {
137  return false;
138  }
139  yCDebug(RFMODULE, "command received: %s\n", cmd.toString().c_str());
140 
141  bool result = owner.safeRespond(cmd, response);
142  if (response.size() >= 1) {
143  ConnectionWriter* writer = connection.getWriter();
144  if (writer != nullptr) {
145  if (response.get(0).toString() == "many" && writer->isTextMode()) {
146  for (size_t i = 1; i < response.size(); i++) {
147  Value& v = response.get(i);
148  if (v.isList()) {
149  v.asList()->write(*writer);
150  } else {
151  Bottle b;
152  b.add(v);
153  b.write(*writer);
154  }
155  }
156  } else {
157  response.write(*writer);
158  }
159  yCDebug(RFMODULE, "response sent: %s\n", response.toString().c_str());
160  }
161  }
162  return result;
163 }
164 
165 
167 {
168 private:
169  RFModule& owner;
170 
171 public:
173  owner(owner)
174  {
175  }
176 
177  void run() override
178  {
179  owner.runModule();
180  }
181 };
182 
183 
185 {
186 private:
187  RFModule& owner;
188  bool singleton_run_module;
189 
190 public:
193 
194  Private(RFModule& owner) :
195  owner(owner),
196  singleton_run_module(false),
197  respond_handler(nullptr),
198  threaded_handler(nullptr)
199  {
200  respond_handler = new RFModuleRespondHandler(owner);
201  }
202 
204  {
205  delete respond_handler;
206  delete threaded_handler;
207  }
208 
210  {
211  threaded_handler = new RFModuleThreadedHandler(owner);
212 
213  return threaded_handler != nullptr;
214  }
215 
217  {
218  delete threaded_handler;
219  threaded_handler = nullptr;
220  }
221 
222 
224  {
225  return singleton_run_module;
226  }
228  {
229  singleton_run_module = true;
230  }
231 };
232 
233 
234 static RFModule* module = nullptr;
235 
237 {
238  if (mPriv->threaded_handler != nullptr) {
239  return mPriv->threaded_handler->getKey();
240  }
242 }
243 
244 static void handler(int sig)
245 {
246  YARP_UNUSED(sig);
247  static int ct = 0;
248  ct++;
250  if (ct > 3) {
251  yCInfo(RFMODULE, "Aborting (calling abort())...");
252  std::abort();
253  }
254  yCInfo(RFMODULE, "[try %d of 3] Trying to shut down.", ct);
255 
256  if (module != nullptr) {
257  module->stopModule(false);
258  }
259 
260 #if defined(_WIN32)
261  // on windows we need to reset the handler after being called, otherwise it
262  // will not be called anymore.
263  // see http://www.geeksforgeeks.org/write-a-c-program-that-doesnt-terminate-when-ctrlc-is-pressed/
264 
265  // Additionally, from
266  // http://www.linuxprogrammingblog.com/all-about-linux-signals?page=show
267  // The signal(2) function is the oldest and simplest way to install a signal
268  // handler but it's deprecated.
269  // There are few reasons and most important is that the original Unix
270  // implementation would reset the signal handler to it's default value after
271  // signal is received.
272  ::signal(SIGINT, handler);
273 #endif
274 }
275 
276 // Special case for windows. Do not return, wait for the the main thread to
277 // return. In any case windows will shut down the application after a timeout
278 // of 5 seconds. This wait is required otherwise windows shuts down the process
279 // after we return from the signal handler. We could not find better way to
280 // handle clean remote shutdown of processes in windows.
281 #if defined(_WIN32)
282 static void handler_sigbreak(int sig)
283 {
284  yarp::os::impl::raise(SIGINT);
285 }
286 #endif
287 
288 
290  stopFlag(false),
291  mPriv(nullptr)
292 {
294 
295  mPriv = new Private(*this);
296 
297  //set up signal handlers for catching ctrl-c
298  if (module == nullptr) {
299  module = this;
300  } else {
301  yCInfo(RFMODULE, "RFModule::RFModule() signal handling currently only good for one module.");
302  }
303 
304 #if defined(_WIN32)
305  yarp::os::impl::signal(SIGBREAK, handler_sigbreak);
306 #endif
307 
308  yarp::os::impl::signal(SIGINT, handler);
309  yarp::os::impl::signal(SIGTERM, handler);
310 }
311 
312 
314 {
315  delete mPriv;
317 }
318 
319 
321 {
322  return 1.0;
323 }
324 
325 
327 {
328  if (mPriv->getSingletonRunModule()) {
329  return 1;
330  }
331  mPriv->setSingletonRunModule();
332 
333  // Setting up main loop
334  // Use yarp::os::Time
335  double currentRun;
336  double elapsed;
337  double sleepPeriod;
338 
339  while (!isStopping()) {
340  currentRun = yarp::os::Time::now();
341  // If updateModule() returns false we exit the main loop.
342  if (!updateModule()) {
343  break;
344  }
345 
346  // At the end of each run of updateModule function, the thread is supposed
347  // to be suspended and release CPU to other threads.
348  // Calling a yield here will help the threads to alternate in the execution.
349  // Note: call yield BEFORE computing elapsed time, so that any time spent due to
350  // yield is took into account and the sleep time is correct.
352 
353  // The module is stopped for getPeriod() seconds.
354  // If getPeriod() returns a time > 1 second, we check every second if
355  // the module stopping, and eventually we exit the main loop.
356  do {
357  elapsed = yarp::os::Time::now() - currentRun;
358  sleepPeriod = getPeriod() - elapsed;
359  if (sleepPeriod > 1) {
360  Time::delay(1.0);
361  } else {
362  Time::delay(sleepPeriod);
363  break;
364  }
365  } while (!isStopping());
366  }
367 
368  yCInfo(RFMODULE, "RFModule closing.");
369  if (mPriv->respond_handler->isTerminalAttached()) {
370  yCWarning(RFMODULE, "Module attached to terminal calling exit() to quit.");
371  yCWarning(RFMODULE, "You should be aware that this is not a good way to stop a module. Effects will be:");
372  yCWarning(RFMODULE, "- class destructors will NOT be called");
373  yCWarning(RFMODULE, "- code in the main after runModule() will NOT be executed");
374  yCWarning(RFMODULE, "This happens because in your module you called attachTerminal() and we don't have a portable way to quit a module that is listening to the terminal.");
375  yCWarning(RFMODULE, "At the moment the only way to have the module quit correctly is to avoid listening to terminal (i.e. do not call attachTerminal()).");
376  yCWarning(RFMODULE, "This will also make this annoying message go away.");
377 
378  // One day this will hopefully go away, now only way to stop
379  // remove both:
380  close();
381  std::exit(1);
383  detachTerminal();
384  }
385 
386  close();
387  yCInfo(RFMODULE, "RFModule finished.");
388  return 0;
389 }
390 
391 
393 {
394  if (mPriv->getSingletonRunModule()) {
395  return 1;
396  }
397 
398  if (!configure(rf)) {
399  yCInfo(RFMODULE, "RFModule failed to open.");
400  return 1;
401  }
402  return runModule();
403 }
404 
405 
407 {
408  if (mPriv->getSingletonRunModule()) {
409  return 1;
410  }
411 
412  if (!mPriv->newThreadHandler()) {
413  yCError(RFMODULE, "RFModule handling thread failed to allocate.");
414  return 1;
415  }
416 
417  if (!mPriv->threaded_handler->start()) {
418  yCError(RFMODULE, "RFModule handling thread failed to start.");
419  return 1;
420  }
421 
422  return 0;
423 }
424 
425 
427 {
428  if (mPriv->getSingletonRunModule()) {
429  return 1;
430  }
431 
432  if (!configure(rf)) {
433  yCError(RFMODULE, "RFModule failed to open.");
434  return 1;
435  }
436 
437  return runModuleThreaded();
438 }
439 
440 
442 {
443  YARP_UNUSED(rf);
444  return true;
445 }
446 
447 
448 bool RFModule::respond(const Bottle& command, Bottle& reply)
449 {
450  return basicRespond(command, reply);
451 }
452 
453 
460 {
461  mPriv->respond_handler->attach(source);
462  return true;
463 }
464 
465 
467 {
468  mPriv->respond_handler->attach(source);
469  return true;
470 }
471 
472 
474 {
475  mPriv->respond_handler->attachTerminal();
476  return true;
477 }
478 
479 
481 {
482  mPriv->respond_handler->detachTerminal();
483  return true;
484 }
485 
486 
488 {
489  return true;
490 }
491 
492 
494 {
495  return true;
496 }
497 
498 
499 void RFModule::stopModule(bool wait)
500 {
501  stopFlag = true;
502 
503  if (!interruptModule()) {
504  yCError(RFMODULE, "interruptModule() returned an error there could be problems shutting down the module.");
505  }
506 
507  if (wait) {
508  joinModule();
509  }
510 }
511 
512 
514 {
515  return stopFlag;
516 }
517 
518 
519 bool RFModule::joinModule(double seconds)
520 {
521  if (mPriv->threaded_handler != nullptr) {
522  if (mPriv->threaded_handler->join(seconds)) {
523  mPriv->deleteThreadHandler();
524  return true;
525  }
526  yCWarning(RFMODULE, "RFModule joinModule() timed out.");
527  return false;
528  }
529  yCWarning(RFMODULE, "Cannot call join: RFModule runModule() is not currently threaded.");
530  return true;
531 }
532 
533 
534 std::string RFModule::getName(const std::string& subName)
535 {
536  if (subName.empty()) {
537  return name;
538  }
539 
540  std::string base = name;
541 
542  // Support legacy behavior, check if a "/" needs to be
543  // appended before subName.
544  if (subName[0] != '/') {
545  yCWarning(RFMODULE, "SubName in getName() does not begin with \"/\" this suggest you expect getName() to follow a deprecated behavior.");
546  yCWarning(RFMODULE, "I am now adding \"/\" between %s and %s but you should not rely on this.", name.c_str(), subName.c_str());
547 
548  base += "/";
549  }
550 
551  base += subName;
552  return base;
553 }
554 
555 
556 void RFModule::setName(const char* name)
557 {
558  this->name = name;
559 }
560 
561 
562 bool RFModule::safeRespond(const Bottle& command, Bottle& reply)
563 {
564  bool ok = respond(command, reply);
565  if (!ok) {
566  // just in case derived classes don't correctly pass on messages
567  ok = basicRespond(command, reply);
568  }
569  return ok;
570 }
571 
572 
573 bool RFModule::basicRespond(const Bottle& command, Bottle& reply)
574 {
575  switch (command.get(0).asVocab()) {
576  case yarp::os::createVocab('q', 'u', 'i', 't'):
577  case yarp::os::createVocab('e', 'x', 'i', 't'):
578  case yarp::os::createVocab('b', 'y', 'e'):
579  reply.addVocab(Vocab::encode("bye"));
580  stopModule(false); //calls interruptModule()
581  return true;
582  default:
583  reply.addString("command not recognized");
584  return false;
585  }
586  return false;
587 }
yarp::os::RFModule
A base-class for standard YARP modules that supports ResourceFinder.
Definition: RFModule.h:23
RFModuleRespondHandler::attach
bool attach(yarp::os::RpcServer &source)
Definition: RFModule.cpp:100
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:72
yarp::os::Value::asVocab
virtual std::int32_t asVocab() const
Get vocabulary identifier as an integer.
Definition: Value.cpp:231
yarp::os::RFModule::stopModule
void stopModule(bool wait=false)
Ask the module to stop.
Definition: RFModule.cpp:499
yarp::os::Bottle::toString
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition: Bottle.cpp:214
yarp::os::createVocab
constexpr yarp::conf::vocab32_t createVocab(char a, char b=0, char c=0, char d=0)
Definition: Vocab.h:22
Network.h
yarp::sig::file::read
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:656
RFModuleThreadedHandler::RFModuleThreadedHandler
RFModuleThreadedHandler(RFModule &owner)
Definition: RFModule.cpp:172
RFModuleThreadedHandler
Definition: RFModule.cpp:166
yarp::os::Bottle::size
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:254
RFModuleRespondHandler::attachTerminal
bool attachTerminal()
Definition: RFModule.cpp:108
yarp::os::RFModule::detachTerminal
bool detachTerminal()
Detach terminal.
Definition: RFModule.cpp:480
yCWarning
#define yCWarning(component,...)
Definition: LogComponent.h:146
ConnectionWriter.h
YARP_UNUSED
#define YARP_UNUSED(var)
Definition: api.h:159
RFModuleRespondHandler::read
bool read(yarp::os::ConnectionReader &connection) override
Handler for reading messages from the network, and passing them on to the respond() method.
Definition: RFModule.cpp:132
yarp::os::RFModule::isStopping
bool isStopping()
Check if the module should stop.
Definition: RFModule.cpp:513
yarp::os::RFModule::Private::getSingletonRunModule
bool getSingletonRunModule()
Definition: RFModule.cpp:223
yarp::os::RFModule::attachTerminal
bool attachTerminal()
Make any input from standard input (usually the keyboard) go to the respond() method.
Definition: RFModule.cpp:473
yarp::os::RFModule::setName
void setName(const char *name)
Set the name of the module.
Definition: RFModule.cpp:556
yarp::os::RFModule::joinModule
bool joinModule(double seconds=-1)
The function returns when the thread execution has completed.
Definition: RFModule.cpp:519
RFModuleRespondHandler::attach
bool attach(yarp::os::Port &source)
Definition: RFModule.cpp:92
yarp::os::RFModule::RFModule
RFModule()
Constructor.
Definition: RFModule.cpp:289
yarp::os::NetworkBase::initMinimum
static void initMinimum()
Basic system initialization, not including plugins.
Definition: Network.cpp:874
yarp::os::Thread
Definition: Thread.h:24
yarp::os::RFModule::interruptModule
virtual bool interruptModule()
Try to halt any ongoing operations by threads managed by the module.
Definition: RFModule.cpp:487
LogComponent.h
yarp::os::RFModule::getName
std::string getName(const std::string &subName="")
Return name of module, as set with setName().
Definition: RFModule.cpp:534
RFModuleRespondHandler::isTerminalAttached
bool isTerminalAttached()
Definition: RFModule.cpp:117
RFModuleRespondHandler::run
void run() override
Main body of the new thread.
Definition: RFModule.cpp:62
yarp::os::RFModule::safeRespond
bool safeRespond(const Bottle &command, Bottle &reply)
Wrapper around respond() that is guaranteed to process system messages.
Definition: RFModule.cpp:562
yarp::os::Time::now
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
RFModuleRespondHandler
Definition: RFModule.cpp:35
yarp::os::Port
Definition: Port.h:49
yarp::os::RFModule::updateModule
virtual bool updateModule()=0
Override this to do whatever your module needs to do.
yarp::os::RFModule::Private::threaded_handler
RFModuleThreadedHandler * threaded_handler
Definition: RFModule.cpp:192
yarp::os::RFModule::runModuleThreaded
virtual int runModuleThreaded()
Calls updateModule() on a separate thread until that returns false.
Definition: RFModule.cpp:406
yarp::os::RFModule::getThreadKey
virtual int getThreadKey()
return the Thread unique identifier
Definition: RFModule.cpp:236
yarp::os::Time::useSystemClock
void useSystemClock()
Configure YARP to use system time (this is the default).
Definition: Time.cpp:147
yarp::os::RFModule::Private::~Private
~Private()
Definition: RFModule.cpp:203
yarp::os::impl::Terminal::readString
std::string readString(bool *eof)
Definition: Terminal.cpp:79
yarp::os::RFModule::Private::deleteThreadHandler
void deleteThreadHandler()
Definition: RFModule.cpp:216
yarp::os::PortReader
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:27
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
yarp::os::Bottle::write
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:233
yarp::os::ConnectionWriter
An interface for writing to a network connection.
Definition: ConnectionWriter.h:39
yarp::os::Thread::getKeyOfCaller
static long int getKeyOfCaller()
Get a unique identifier for the calling thread.
Definition: Thread.cpp:133
handler
static void handler(int sig)
Definition: RFModule.cpp:244
yarp::os::RFModule::attach
virtual bool attach(yarp::os::Port &source)
Make any input from a Port object go to the respond() method.
Definition: RFModule.cpp:459
RFModuleRespondHandler::detachTerminal
bool detachTerminal()
Definition: RFModule.cpp:123
Os.h
yarp::os::Time::yield
void yield()
The calling thread releases its remaining quantum upon calling this function.
Definition: Time.cpp:141
yarp::os::RpcServer
Definition: RpcServer.h:26
Thread.h
module
static RFModule * module
Definition: RFModule.cpp:234
yarp::os::Vocab::encode
NetInt32 encode(const std::string &str)
Convert a string into a vocabulary identifier.
Definition: Vocab.cpp:14
RFModule.h
yarp::os::ConnectionReader::getWriter
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
yarp::os::RFModule::respond
virtual bool respond(const Bottle &command, Bottle &reply)
Respond to a message.
Definition: RFModule.cpp:448
yarp::os::NetworkBase::finiMinimum
static void finiMinimum()
Deinitialization, excluding plugins.
Definition: Network.cpp:942
yarp::os::RFModule::configure
virtual bool configure(yarp::os::ResourceFinder &rf)
Configure the module, pass a ResourceFinder object to the module.
Definition: RFModule.cpp:441
yarp::os::Bottle::addString
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:173
yarp::os::Port::setReader
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: Port.cpp:505
yarp::os::RFModule::Private::Private
Private(RFModule &owner)
Definition: RFModule.cpp:194
yarp::os::Value::isList
virtual bool isList() const
Checks if value is a list.
Definition: Value.cpp:165
yarp::os::RFModule::~RFModule
virtual ~RFModule()
Destructor.
Definition: RFModule.cpp:313
yarp::os::RFModule::Private
Definition: RFModule.cpp:184
yarp::os::ConnectionReader
An interface for reading from a network connection.
Definition: ConnectionReader.h:39
yarp::os::RFModule::Private::setSingletonRunModule
void setSingletonRunModule()
Definition: RFModule.cpp:227
RFModuleRespondHandler::RFModuleRespondHandler
RFModuleRespondHandler(RFModule &owner)
Definition: RFModule.cpp:54
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::ConnectionWriter::isTextMode
virtual bool isTextMode() const =0
Check if the connection is text mode.
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
PlatformSignal.h
yarp::os
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
yarp
Definition: environment.h:18
Terminal.h
Vocab.h
yarp::os::RFModule::runModule
virtual int runModule()
Calls updateModule() until that returns false.
Definition: RFModule.cpp:326
yarp::os::Bottle::read
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:243
RFModuleThreadedHandler::run
void run() override
Main body of the new thread.
Definition: RFModule.cpp:177
yarp::os::Value::asList
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:243
yarp::os::RFModule::Private::newThreadHandler
bool newThreadHandler()
Definition: RFModule.cpp:209
yarp::os::Thread::start
bool start()
Start the new thread running.
Definition: Thread.cpp:96
Time.h
yarp::os::Bottle::add
void add(const Value &value)
Add a Value to the bottle, at the end of the list.
Definition: Bottle.cpp:339
yarp::os::Value::toString
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Value.cpp:359
yarp::os::Value
A single value (typically within a Bottle).
Definition: Value.h:46
yarp::os::Thread::stop
bool stop()
Stop the thread.
Definition: Thread.cpp:84
PlatformTime.h
YARP_OS_LOG_COMPONENT
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:37
yarp::os::impl
yarp::os::Time::delay
void delay(double seconds)
Wait for a certain number of seconds.
Definition: Time.cpp:114
Bottle.h
yarp::os::RFModule::Private::respond_handler
RFModuleRespondHandler * respond_handler
Definition: RFModule.cpp:191
yarp::os::RFModule::getPeriod
virtual double getPeriod()
You can override this to control the approximate periodicity at which updateModule() is called by run...
Definition: RFModule.cpp:320
yarp::os::AbstractContactable::setReader
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: AbstractContactable.cpp:104
yarp::os::ResourceFinder
Helper class for finding config files and other external resources.
Definition: ResourceFinder.h:32
yarp::os::RFModule::close
virtual bool close()
Close function.
Definition: RFModule.cpp:493