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 (e.g. opencv_grabber
396 // apparently).
397 options.put("single_threaded", 1);
398
399 // interpret command line options as a set of flags
400 //options.fromCommand(argc,argv,true,false);
401 options.fromString(rf.toString(), false);
402
403 // check if we're being asked to read the options from file
404 Value *val;
405 if (options.check("file",val)) {
406 yCError(DRIVERS, "*** yarpdev --file is deprecated, please use --from");
407 return 0;
408 }
409
410 // print the full list of devices, if requested
411 if (options.check("list")) {
412 yCInfo(DRIVERS, "Here are devices listed for your system:");
413 for (const auto& s : yarp::conf::string::split(Drivers::factory().toString(), '\n')) {
414 yCInfo(DRIVERS, "%s", s.c_str());
415 }
416 return 0;
417 }
418
419 // check if we want to use nested options (less ambiguous)
420 if (options.check("nested", val) || options.check("lispy", val)) {
421 std::string lispy = val->toString();
422 yCDebug(DRIVERS, "yarpdev: working with config %s", lispy.c_str());
423 options.fromString(lispy);
424 }
425
426 // no device mentioned, neither in the option, nor in configuration file - maybe user needs help
427 if (!options.check("device") && !options.check("from"))
428 {
429 yCInfo(DRIVERS, "Welcome to yarpdev, a program to create YARP devices");
430 yCInfo(DRIVERS, "To see the devices available, try:");
431 yCInfo(DRIVERS, " yarpdev --list");
432 yCInfo(DRIVERS, "To create a device whose name you know, call yarpdev like this:");
433 yCInfo(DRIVERS, " yarpdev --device DEVICENAME --OPTION VALUE ...");
434 yCInfo(DRIVERS, " For example:");
435 yCInfo(DRIVERS, " yarpdev --device fakeFrameGrabber --width 32 --height 16 --name /grabber");
436 yCInfo(DRIVERS, "If the device supports it, you can check its configuration parameters using the --help option");
437 yCInfo(DRIVERS, "You can always move options to a configuration file:");
438 yCInfo(DRIVERS, " yarpdev [--device DEVICENAME] --from CONFIG_FILENAME");
439 yCError(DRIVERS,"Device name not specified");
440 return 0;
441 }
442
443 //The following syntax is deprecated: generate an error!
444 if (options.check("device") && options.check("subdevice"))
445 {
446 std::string dev_name = options.find("device").asString();
447 std::string subdev_name = options.find("subdevice").asString();
448 yCError(DRIVERS, "The syntax:");
449 yCError(DRIVERS, "yarpdev --device %s --subdevice %s", dev_name.c_str(), subdev_name.c_str());
450 yCError(DRIVERS, "has been deprecated.");
451 yCError(DRIVERS, "Use the following command line instead:");
452 yCError(DRIVERS, "yarpdev --device deviceBundler --wrapper_device %s --attached_device %s", dev_name.c_str(), subdev_name.c_str());
453 return 0;
454 }
455
456 //yarpdev enables the wrapping mechanism, which is not enabled by default if,
457 //for example a device is opened from the code, using PolyDriver.open()
458 //When enabled, it asks for a wrapped, remotable device rather than raw device
459 options.put("wrapping_enabled","1");
460
461 //YarpDevMonitor monitor;
462 if (options.check("verbose")) {
463 yCWarning(DRIVERS, "The verbose option is deprecated.");
464 }
465
466 // we now need network
467 bool ret=Network::checkNetwork();
468 if (!ret) {
469 yCError(DRIVERS, "YARP network not available, check if yarp server is reachable");
470 return -1;
471 }
472
473 //
474 // yarpdev initializes the clock only before starting to do real thing.
475 // This way yarpdev --lish/help will not be affected by network clock.
476 //
477 // Shall other devices be affected by network clock ??
478 // Hereafter the device may need to use the SystemClock or the NetworkClock
479 // depending by the device, a real or a fake / simulated one.
480 // Using the YARP_CLOCK_DEFAULT the behaviour will be determined by the
481 // environment variable.
482 //
484
485 // Finally open the device driver
486 PolyDriver dd(options);
487 std::string id = dd.id();
488
489 //if the device.open() failed...
490 if (!dd.isValid())
491 {
492 yCIError(DRIVERS, id, "yarpdev: ***ERROR*** device not available.");
493 yCIInfo(DRIVERS, id, "+ Suggestions:");
494 //The following code print suggestions, i.e. devices with similar names
496 yps.scan();
497 yarp::os::Bottle b = yps.getSelectedPlugins();
498 std::string dev_name = options.find("device").asString();
499 for (size_t i = 0; i < b.size(); i++)
500 {
501 Value& plugv = b.get(i);
502 std::string similar_name = plugv.check("name", Value("untitled")).asString();
504 if (distance < 5)
505 {
506 yCIInfo(DRIVERS, id, "%s", similar_name.c_str());
507 }
508 else
509 {
510 std::string lowerStr = toLowerCase(similar_name);
511 std::string lowerSub = toLowerCase(dev_name);
512 if (lowerStr.find(lowerSub) != std::string::npos)
513 {
514 yCIInfo(DRIVERS, id, "%s", similar_name.c_str());
515 }
516 }
517 }
518 yCIInfo(DRIVERS, id, "+ Do \"yarpdev --list\" to see list of supported devices.");
519 return 1;
520 }
521
522 Terminee *terminee = nullptr;
523 if (dd.isValid())
524 {
525 Value *v;
526 std::string name;
527 if (options.check("name", v))
528 {
529 name = v->toString();
530 }
531 if (name.empty() && options.check("device", v))
532 {
533 //get the name of the device from the polydriver
534 //TO BE IMPLEMENTED. FOR REFERENCE ONLY:
535 //name = dd.getDefaultValue((device_name + ".name").c_str()).toString();
536 }
537 if (name.empty())
538 {
539 name = "/yarpdev";
540 }
541 std::string s = name + "/quit";
542
543 if (s.find('=') == std::string::npos &&
544 s.find('@') == std::string::npos) {
545 terminee = new Terminee(s.c_str());
546 terminatorKey = s;
547 if (terminee == nullptr) {
548 yCIError(DRIVERS, id, "Can't allocate terminator port");
549 terminatorKey = "";
550 dd.close();
551 return 1;
552 }
553 if (!terminee->isOk()) {
554 yCIError(DRIVERS, id, "Failed to create terminator port");
555 terminatorKey = "";
556 delete terminee;
557 terminee = nullptr;
558 dd.close();
559 return 1;
560 }
561 }
562 }
563
564 double dnow = 3;
565 double startTime = Time::now()-dnow;
566 IService *service = nullptr;
567 dd.view(service);
568 if (service!=nullptr) {
569 bool backgrounded = service->startService();
570 if (backgrounded) {
571 // we don't need to poll this, so forget about the
572 // service interface
573 yCIDebug(DRIVERS, id, "yarpdev: service backgrounded");
574 service = nullptr;
575 }
576 }
577 while (dd.isValid() && !(terminated||(terminee&&terminee->mustQuit()))) {
578 if (service!=nullptr) {
579 double now = Time::now();
580 if (now-startTime>dnow) {
581 yCIInfo(DRIVERS, id, "device active...");
582 startTime += dnow;
583 }
584 // we requested single threading, so need to
585 // give the device its chance
586 if(!service->updateService()) {
587 if(!service->stopService()) {
588 yCIWarning(DRIVERS, id, "Error while stopping device");
589 }
590 terminated = true;
591 }
592 } else {
593 // we don't need to do anything
594 yCIInfo(DRIVERS, id, "device active in background...");
596 }
597 }
598
599 if (terminee) {
600 delete terminee;
601 terminee = nullptr;
602 }
603 dd.close();
604
605 yCIInfo(DRIVERS, id, "yarpdev is finished.");
606
607 return 0;
608}
609
611 yCTrace(DRIVERS, "Creating %s from %s", desc.c_str(), libname.c_str());
612 auto* result = new StubDriver(libname.c_str(),fnname.c_str());
613 if (result==nullptr) {
614 return result;
615 }
616 if (!result->isValid()) {
617 delete result;
618 result = nullptr;
619 return nullptr;
620 }
621 yCTrace(DRIVERS, "Created %s from %s", desc.c_str(), libname.c_str());
622 return result;
623}
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:610
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.
Definition jointData.cpp:13
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