YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Drivers.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <yarp/dev/Drivers.h>
8
9#include <yarp/conf/string.h>
10
11#include <yarp/os/Log.h>
13#include <yarp/os/Os.h>
14#include <yarp/os/Property.h>
16#include <yarp/os/Time.h>
17#include <yarp/os/Network.h>
18#include <yarp/os/Terminator.h>
19#include <yarp/os/YarpPlugin.h>
20#include <yarp/dev/PolyDriver.h>
23
24#include <vector>
25#include <sstream>
26#include <iterator>
27#include <csignal>
28
29using namespace yarp::os;
30using namespace yarp::dev;
31
32namespace {
33YARP_LOG_COMPONENT(DRIVERS, "yarp.dev.Drivers")
34}
35
37public:
38 std::vector<DriverCreator *> delegates;
39
40 ~Private() override {
41 for (auto& delegate : delegates) {
42 if (delegate==nullptr) {
43 continue;
44 }
45 delete delegate;
46 }
47 delegates.clear();
48 }
49
50 bool select(Searchable& options) override {
51 return options.check("type",Value("none")).asString() == "device";
52 }
53
54 std::string toString() {
55 std::string s;
56 Property done;
57 for (auto& delegate : delegates) {
58 if (delegate==nullptr) {
59 continue;
60 }
61 std::string name = delegate->getName();
62 done.put(name,1);
63 std::string wrapper = delegate->getWrapper();
64 s += "Device \"";
65 s += delegate->getName();
66 s += "\"";
67 s += ",";
68 s += " C++ class ";
69 s += delegate->getCode();
70 s += ", ";
71 if (wrapper.empty()) {
72 s += "has no network wrapper";
73 } else if (wrapper!=name) {
74 s += "wrapped by \"";
75 s += delegate->getWrapper();
76 s += "\"";
77 } else {
78 s += "is a network wrapper.";
79 }
80 s += "\n";
81 }
82
83 scan();
85 for (size_t i=0; i<lst.size(); i++) {
86 Value& prop = lst.get(i);
87 std::string name = prop.check("name",Value("untitled")).asString();
88 if (done.check(name)) {
89 continue;
90 }
91
93 YarpPluginSettings settings;
94 settings.setSelector(*this);
95 settings.readFromSearchable(prop,name);
96 settings.open(lib);
97 std::string location = lib.getName();
98 if (location.empty()) {
99 // A wrong library name ends up with empty location
100 yCWarning(DRIVERS, "Wrong library name for plugin %s", name.c_str());
101 continue;
102 }
103
104 std::string cxx = prop.check("cxx",Value("unknown")).asString();
105 std::string wrapper = prop.check("wrapper",Value("unknown")).asString();
106 s += "Device \"";
107 s += name;
108 s += "\"";
109 s += ",";
110 s += " available on request (found in ";
111 s += location;
112 s += " library)";
113 if (cxx!="unknown") {
114 s += ", C++ class ";
115 s += cxx;
116 s += " ";
117 }
118
119 if (wrapper.empty()) {
120 s += "no network wrapper known"; // will never come here since the prop.check fallback is set to unknown few lines above!!!
121 } else if (wrapper=="unknown") {
122 //s += "network wrapper unknown";
123 } else if (wrapper!=name) {
124 s += ", wrapped by \"";
125 s += wrapper;
126 s += "\"";
127 } else {
128 s += ", is a network wrapper";
129 }
130 s += ".\n";
131 }
132
133 return s;
134 }
135
137 if (creator!=nullptr) {
138 delegates.push_back(creator);
139 }
140 }
141
142 DriverCreator *load(const char *name);
143
144 DriverCreator *find(const char *name) {
145 for (auto& delegate : delegates) {
146 if (delegate == nullptr) {
147 continue;
148 }
149 std::string s = delegate->toString();
150 if (s==name) {
151 return delegate;
152 }
153 }
154 return load(name);
155 }
156
157 bool remove(const char *name) {
158 for (auto& delegate : delegates) {
159 if (delegate == nullptr) {
160 continue;
161 }
162 std::string s = delegate->toString();
163 if (s==name) {
164 delete delegate;
165 delegate = nullptr;
166 }
167 }
168 return false;
169 }
170};
171
172class StubDriver : public DeviceDriver {
173private:
174 YarpPluginSettings settings;
177public:
178 StubDriver(const char *dll_name, const char *fn_name) {
179 settings.setLibraryMethodName(dll_name,fn_name);
180 init();
181 }
182
183 StubDriver(const char *name) {
184 settings.setPluginName(name);
185 YarpPluginSelector selector;
186 selector.scan();
187 if (!settings.setSelector(selector)) {
188 return;
189 }
190 init();
191 }
192
193 virtual ~StubDriver() = default;
194
195 void init() {
196 if (plugin.open(settings)) {
197 dev.open(*plugin.getFactory());
198 settings.setLibraryMethodName(plugin.getFactory()->getName(),
199 settings.getMethodName());
200 settings.setClassInfo(plugin.getFactory()->getClassName(),
201 plugin.getFactory()->getBaseClassName());
202 }
203 }
204
205 bool isValid() const {
206 return dev.isValid();
207 }
208
209 bool open(yarp::os::Searchable& config) override {
210 if (!isValid()) {
211 return false;
212 }
213 return dev.getContent().open(config);
214 }
215
216 bool close() override {
217 if (!isValid()) {
218 return false;
219 }
220 return dev.getContent().close();
221 }
222
223 void setId(const std::string& id) override
224 {
225 if (!isValid()) {
226 return;
227 }
228 dev.getContent().setId(id);
229 }
230
231 std::string id() const override
232 {
233 if (!isValid()) {
234 return "StubDriver";
235 }
236 return dev.getContent().id();
237 }
238
240 return &dev.getContent();
241 }
242
243 std::string getDllName() const {
244 return settings.getLibraryName();
245 }
246
247 std::string getFnName() const {
248 return settings.getMethodName();
249 }
250
251 std::string getwrapName() const {
252 return settings.getWrapperName();
253 }
254
255 std::string getPluginName() const {
256 return settings.getPluginName();
257 }
258
259 std::string getClassName() const {
260 return settings.getClassName();
261 }
262
263 std::string getBaseClassName() const {
264 return settings.getBaseClassName();
265 }
266};
267
269{
270 static Drivers instance;
271 return instance;
272}
273
274Drivers::Drivers() :
275 mPriv(new Private)
276{
277}
278
280 delete mPriv;
281}
282
283std::string Drivers::toString() const {
284 return mPriv->toString();
285}
286
288 mPriv->add(creator);
289}
290
291
292DriverCreator *Drivers::find(const char *name) {
293 return mPriv->find(name);
294}
295
296bool Drivers::remove(const char *name) {
297 return mPriv->remove(name);
298}
299
300
302 PolyDriver poly;
303 bool result = poly.open(prop);
304 if (!result) {
305 return nullptr;
306 }
307 return poly.take();
308}
309
311 auto* result = new StubDriver(name);
312 if (!result->isValid()) {
313 delete result;
314 result = nullptr;
315 return nullptr;
316 }
317 DriverCreator *creator = new StubDriverCreator(result->getPluginName().c_str(),
318 result->getwrapName().c_str(),
319 result->getClassName().c_str(),
320 result->getDllName().c_str(),
321 result->getFnName().c_str());
322 add(creator);
323 delete result;
324 return creator;
325}
326
327static std::string terminatorKey;
328static bool terminated = false;
329static void handler (int)
330{
332 static double handleTime = -100;
333 static int ct = 0;
334 double now = Time::now();
335 if (now-handleTime<1) {
336 return;
337 }
338 handleTime = now;
339 ct++;
340 if (ct>3) {
341 yCInfo(DRIVERS, "Aborting...");
342 std::exit(1);
343 }
344 if (!terminatorKey.empty()) {
345 yCInfo(DRIVERS, "[try %d of 3] Trying to shut down %s", ct, terminatorKey.c_str());
346 terminated = true;
348 } else {
349 yCInfo(DRIVERS, "Aborting...");
350 std::exit(1);
351 }
352}
353
354int levenshteinDistance(const std::string& s1, const std::string& s2)
355{
356 int len1 = s1.size();
357 int len2 = s2.size();
358 std::vector<std::vector<int>> dp(len1 + 1, std::vector<int>(len2 + 1));
359
360 for (int i = 0; i <= len1; ++i)
361 dp[i][0] = i;
362 for (int j = 0; j <= len2; ++j)
363 dp[0][j] = j;
364
365 for (int i = 1; i <= len1; ++i) {
366 for (int j = 1; j <= len2; ++j) {
367 if (s1[i - 1] == s2[j - 1])
368 dp[i][j] = dp[i - 1][j - 1];
369 else
370 dp[i][j] = 1 + std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]});
371 }
372 }
373 return dp[len1][len2];
374}
375
376std::string toLowerCase(const std::string& str)
377{
378 std::string lowerStr = str;
379 std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower);
380 return lowerStr;
381}
382
383int Drivers::yarpdev(int argc, char *argv[]) {
384
385 std::signal(SIGINT, handler);
386 std::signal(SIGTERM, handler);
387
388 // get command line options
390 rf.configure(argc, argv); // this will process --from FILE if present
391 Property options;
392
393 // yarpdev will by default try to pass its thread on to the device.
394 // this is because some libraries need configuration and all
395 // access methods done in the same thread.
396 options.put("single_threaded", 1);
397
398 // interpret command line options as a set of flags
399 //options.fromCommand(argc,argv,true,false);
400 options.fromString(rf.toString(), false);
401
402 // check if we're being asked to read the options from file
403 Value *val;
404 if (options.check("file",val)) {
405 yCError(DRIVERS, "*** yarpdev --file is deprecated, please use --from");
406 return 0;
407 }
408
409 // print the full list of devices, if requested
410 if (options.check("list")) {
411 yCInfo(DRIVERS, "Here are devices listed for your system:");
412 for (const auto& s : yarp::conf::string::split(Drivers::factory().toString(), '\n')) {
413 yCInfo(DRIVERS, "%s", s.c_str());
414 }
415 return 0;
416 }
417
418 // check if we want to use nested options (less ambiguous)
419 if (options.check("nested", val) || options.check("lispy", val)) {
420 std::string lispy = val->toString();
421 yCDebug(DRIVERS, "yarpdev: working with config %s", lispy.c_str());
422 options.fromString(lispy);
423 }
424
425 // no device mentioned, neither in the option, nor in configuration file - maybe user needs help
426 if (!options.check("device") && !options.check("from"))
427 {
428 yCInfo(DRIVERS, "Welcome to yarpdev, a program to create YARP devices");
429 yCInfo(DRIVERS, "To see the devices available, try:");
430 yCInfo(DRIVERS, " yarpdev --list");
431 yCInfo(DRIVERS, "To create a device whose name you know, call yarpdev like this:");
432 yCInfo(DRIVERS, " yarpdev --device DEVICENAME --OPTION VALUE ...");
433 yCInfo(DRIVERS, " For example:");
434 yCInfo(DRIVERS, " yarpdev --device fakeFrameGrabber --width 32 --height 16 --name /grabber");
435 yCInfo(DRIVERS, "If the device supports it, you can check its configuration parameters using the --help option");
436 yCInfo(DRIVERS, "You can always move options to a configuration file:");
437 yCInfo(DRIVERS, " yarpdev [--device DEVICENAME] --from CONFIG_FILENAME");
438 yCError(DRIVERS,"Device name not specified");
439 return 0;
440 }
441
442 //The following syntax is deprecated: generate an error!
443 if (options.check("device") && options.check("subdevice"))
444 {
445 std::string dev_name = options.find("device").asString();
446 std::string subdev_name = options.find("subdevice").asString();
447 yCError(DRIVERS, "The syntax:");
448 yCError(DRIVERS, "yarpdev --device %s --subdevice %s", dev_name.c_str(), subdev_name.c_str());
449 yCError(DRIVERS, "has been deprecated.");
450 yCError(DRIVERS, "Use the following command line instead:");
451 yCError(DRIVERS, "yarpdev --device deviceBundler --wrapper_device %s --attached_device %s", dev_name.c_str(), subdev_name.c_str());
452 return 0;
453 }
454
455 //yarpdev enables the wrapping mechanism, which is not enabled by default if,
456 //for example a device is opened from the code, using PolyDriver.open()
457 //When enabled, it asks for a wrapped, remotable device rather than raw device
458 options.put("wrapping_enabled","1");
459
460 //YarpDevMonitor monitor;
461 if (options.check("verbose")) {
462 yCWarning(DRIVERS, "The verbose option is deprecated.");
463 }
464
465 // we now need network
466 bool ret=Network::checkNetwork();
467 if (!ret) {
468 yCError(DRIVERS, "YARP network not available, check if yarp server is reachable");
469 return -1;
470 }
471
472 //
473 // yarpdev initializes the clock only before starting to do real thing.
474 // This way yarpdev --lish/help will not be affected by network clock.
475 //
476 // Shall other devices be affected by network clock ??
477 // Hereafter the device may need to use the SystemClock or the NetworkClock
478 // depending by the device, a real or a fake / simulated one.
479 // Using the YARP_CLOCK_DEFAULT the behaviour will be determined by the
480 // environment variable.
481 //
483
484 // Finally open the device driver
485 PolyDriver dd(options);
486 std::string id = dd.id();
487
488 //if the device.open() failed...
489 if (!dd.isValid())
490 {
491 yCIError(DRIVERS, id, "yarpdev: ***ERROR*** device not available.");
492 yCIInfo(DRIVERS, id, "+ Suggestions:");
493 //The following code print suggestions, i.e. devices with similar names
495 yps.scan();
496 yarp::os::Bottle b = yps.getSelectedPlugins();
497 std::string dev_name = options.find("device").asString();
498 for (size_t i = 0; i < b.size(); i++)
499 {
500 Value& plugv = b.get(i);
501 std::string similar_name = plugv.check("name", Value("untitled")).asString();
503 if (distance < 5)
504 {
505 yCIInfo(DRIVERS, id, "%s", similar_name.c_str());
506 }
507 else
508 {
509 std::string lowerStr = toLowerCase(similar_name);
510 std::string lowerSub = toLowerCase(dev_name);
511 if (lowerStr.find(lowerSub) != std::string::npos)
512 {
513 yCIInfo(DRIVERS, id, "%s", similar_name.c_str());
514 }
515 }
516 }
517 yCIInfo(DRIVERS, id, "+ Do \"yarpdev --list\" to see list of supported devices.");
518 return 1;
519 }
520
521 Terminee *terminee = nullptr;
522 if (dd.isValid())
523 {
524 Value *v;
525 std::string name;
526 if (options.check("name", v))
527 {
528 name = v->toString();
529 }
530 if (name.empty() && options.check("device", v))
531 {
532 //get the name of the device from the polydriver
533 //TO BE IMPLEMENTED. FOR REFERENCE ONLY:
534 //name = dd.getDefaultValue((device_name + ".name").c_str()).toString();
535 }
536 if (name.empty())
537 {
538 name = "/yarpdev";
539 }
540 std::string s = name + "/quit";
541
542 if (s.find('=') == std::string::npos &&
543 s.find('@') == std::string::npos) {
544 terminee = new Terminee(s.c_str());
545 terminatorKey = s;
546 if (terminee == nullptr) {
547 yCIError(DRIVERS, id, "Can't allocate terminator port");
548 terminatorKey = "";
549 dd.close();
550 return 1;
551 }
552 if (!terminee->isOk()) {
553 yCIError(DRIVERS, id, "Failed to create terminator port");
554 terminatorKey = "";
555 delete terminee;
556 terminee = nullptr;
557 dd.close();
558 return 1;
559 }
560 }
561 }
562
563 double dnow = 3;
564 double startTime = Time::now()-dnow;
565 IService *service = nullptr;
566 dd.view(service);
567 if (service!=nullptr) {
568 bool backgrounded = service->startService();
569 if (backgrounded) {
570 // we don't need to poll this, so forget about the
571 // service interface
572 yCIDebug(DRIVERS, id, "yarpdev: service backgrounded");
573 service = nullptr;
574 }
575 }
576 while (dd.isValid() && !(terminated||(terminee&&terminee->mustQuit()))) {
577 if (service!=nullptr) {
578 double now = Time::now();
579 if (now-startTime>dnow) {
580 yCIInfo(DRIVERS, id, "device active...");
581 startTime += dnow;
582 }
583 // we requested single threading, so need to
584 // give the device its chance
585 if(!service->updateService()) {
586 if(!service->stopService()) {
587 yCIWarning(DRIVERS, id, "Error while stopping device");
588 }
589 terminated = true;
590 }
591 } else {
592 // we don't need to do anything
593 yCIInfo(DRIVERS, id, "device active in background...");
595 }
596 }
597
598 if (terminee) {
599 delete terminee;
600 terminee = nullptr;
601 }
602 dd.close();
603
604 yCIInfo(DRIVERS, id, "yarpdev is finished.");
605
606 return 0;
607}
608
610 yCTrace(DRIVERS, "Creating %s from %s", desc.c_str(), libname.c_str());
611 auto* result = new StubDriver(libname.c_str(),fnname.c_str());
612 if (result==nullptr) {
613 return result;
614 }
615 if (!result->isValid()) {
616 delete result;
617 result = nullptr;
618 return nullptr;
619 }
620 yCTrace(DRIVERS, "Created %s from %s", desc.c_str(), libname.c_str());
621 return result;
622}
static std::string terminatorKey
Definition Drivers.cpp:327
int levenshteinDistance(const std::string &s1, const std::string &s2)
Definition Drivers.cpp:354
static bool terminated
Definition Drivers.cpp:328
std::string toLowerCase(const std::string &str)
Definition Drivers.cpp:376
bool ret
static void handler(int sig)
Definition RFModule.cpp:241
classes to handle graceful process termination.
DriverCreator * load(const char *name)
Definition Drivers.cpp:310
void add(DriverCreator *creator)
Definition Drivers.cpp:136
bool remove(const char *name)
Definition Drivers.cpp:157
DriverCreator * find(const char *name)
Definition Drivers.cpp:144
std::vector< DriverCreator * > delegates
Definition Drivers.cpp:38
bool select(Searchable &options) override
Determine whether a plugin is of interest.
Definition Drivers.cpp:50
std::string getPluginName() const
Definition Drivers.cpp:255
virtual ~StubDriver()=default
StubDriver(const char *name)
Definition Drivers.cpp:183
std::string getFnName() const
Definition Drivers.cpp:247
void setId(const std::string &id) override
Set the id for this device.
Definition Drivers.cpp:223
std::string getClassName() const
Definition Drivers.cpp:259
std::string getDllName() const
Definition Drivers.cpp:243
std::string getBaseClassName() const
Definition Drivers.cpp:263
std::string getwrapName() const
Definition Drivers.cpp:251
DeviceDriver * getImplementation() override
Some drivers are bureaucrats, pointing at others.
Definition Drivers.cpp:239
void init()
Definition Drivers.cpp:195
StubDriver(const char *dll_name, const char *fn_name)
Definition Drivers.cpp:178
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Definition Drivers.cpp:209
std::string id() const override
Return the id assigned to the PolyDriver.
Definition Drivers.cpp:231
bool close() override
Close the DeviceDriver.
Definition Drivers.cpp:216
bool isValid() const
Definition Drivers.cpp:205
Interface implemented by all device drivers.
virtual std::string id() const
Return the id assigned to the PolyDriver.
bool view(T *&x)
Get an interface to the device driver.
A base class for factories that create driver objects.
Definition Drivers.h:27
virtual std::string toString() const =0
Returns a simple description of devices the factory can make.
Global factory for devices.
Definition Drivers.h:171
static int yarpdev(int argc, char *argv[])
Body of the yarpdev program for starting device wrappers.
Definition Drivers.cpp:383
virtual ~Drivers()
Destructor.
Definition Drivers.cpp:279
DeviceDriver * open(const char *device)
Create and configure a device, by name.
Definition Drivers.h:189
DriverCreator * find(const char *name)
Find the factory for a named device.
Definition Drivers.cpp:292
static Drivers & factory()
Get the global factory for devices.
Definition Drivers.cpp:268
bool remove(const char *name)
Remove a factory for a named device.
Definition Drivers.cpp:296
void add(DriverCreator *creator)
Add a factory for creating a particular device.
Definition Drivers.cpp:287
virtual std::string toString() const
A description of the available devices.
Definition Drivers.cpp:283
Common interface for devices that act like services (by which we mean they do something for remote us...
virtual bool startService()
Initiate the service, whatever it is.
virtual bool stopService()
Shut down the service, whatever it is.
virtual bool updateService()
Give the service the chance to run for a while.
A container for a device driver.
Definition PolyDriver.h:23
DeviceDriver * take()
Gets the device this object manages.
bool close() override
Close the DeviceDriver.
bool isValid() const
Check if device is valid.
bool open(const std::string &txt)
Construct and configure a device by its common name.
A factory for creating driver objects from DLLs / shared libraries.
Definition Drivers.h:129
DeviceDriver * create() const override
Create a device.
Definition Drivers.cpp:609
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
size_type size() const
Gets the number of elements in the bottle.
Definition Bottle.cpp:251
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
A mini-server for performing network communication in the background.
std::string getName() const override
Get name of port.
void close() override
Stop port activity.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
static void yarpClockInit(yarp::os::yarpClockType clockType, Clock *custom=nullptr)
This function specifically initialize the clock In case clockType is one of the valid cases: YARP_CLO...
Definition Network.cpp:958
A class for storing options and configuration information.
Definition Property.h:33
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition Property.cpp:987
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Helper class for finding config files and other external resources.
bool configure(int argc, char *argv[], bool skipFirstArgument=true)
Sets up the ResourceFinder.
std::string toString() const override
Return a standard text representation of the content of the object.
A base class for nested structures that can be searched.
Definition Searchable.h:31
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
A wrapper for a named factory method in a named shared library.
std::string getName() const
Get the name associated with this factory.
static void delaySystem(double seconds)
static bool terminateByName(const char *name)
Send a quit message to a specific socket port.
A class that can be polled to see whether the process has been asked to quit gracefully.
Definition Terminator.h:47
A single value (typically within a Bottle).
Definition Value.h:43
std::string toString() const override
Return a standard text representation of the content of the object.
Definition Value.cpp:356
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition Value.cpp:321
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
Pick out a set of relevant plugins.
void scan()
Find plugin configuration files, and run [plugin] sections through the select method.
Collect hints for finding a particular plugin.
bool setSelector(YarpPluginSelector &selector)
Use a selector to find a plugin or plugins.
void setLibraryMethodName(const std::string &dll_name, const std::string &fn_name)
Set the name of the library to load and the method name to use as a factory.
bool open(SharedLibraryFactory &factory)
Initialize a factory object based on the hints available.
bool readFromSearchable(Searchable &options, const std::string &name)
Configure settings from a configuration file or other searchable object.
void setPluginName(const std::string &name)
Set the name of the plugin to load.
std::string getBaseClassName() const
void setClassInfo(const std::string &class_name, const std::string &baseclass_name)
Set the information about the class and the base class constructed by this plugin.
#define yCInfo(component,...)
#define yCError(component,...)
#define yCTrace(component,...)
#define yCWarning(component,...)
#define yCIError(component, id,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
#define yCIInfo(component, id,...)
#define yCIDebug(component, id,...)
#define yCIWarning(component, id,...)
ContainerT split(const typename ContainerT::value_type &s, std::basic_regex< typename ContainerT::value_type::value_type > regex)
Utility to split a string by a separator, into a vector of strings.
Definition string.h:26
For streams capable of holding different kinds of content, check what they actually have.
void useSystemClock()
Configure YARP to use system time (this is the default).
Definition Time.cpp:137
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
An interface to the operating system, including Port based communication.
@ YARP_CLOCK_DEFAULT
Definition Time.h:27