YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Device.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7
11
12#include <yarp/os/LogStream.h>
13#include <yarp/os/Property.h>
14#include <yarp/os/Semaphore.h>
15
19#include <yarp/dev/IWrapper.h>
20#include <yarp/dev/PolyDriver.h>
21
22#include <string>
23
24namespace {
25YARP_LOG_COMPONENT(YRI_DEVICE, "yarp.yri.Device")
26}
27
29{
30
31public:
45
46 Private(Device* /*parent*/) :
47 driver(new Driver(new yarp::dev::PolyDriver()))
48 {
49 }
50
51 Private(const Private& other) :
52 driver(other.driver)
53 {
54 ++driver->ref;
55 }
56
57 Private& operator=(const Private& other)
58 {
59 YARP_UNUSED(other);
60 YARP_FIXME_NOTIMPLEMENTED("operator=")
61 return *this;
62 }
63
65 {
66 if (!--driver->ref) {
68
69 if (driver->driver->isValid()) {
70 if (!driver->driver->close()) {
71 yCWarning(YRI_DEVICE) << "Cannot close device" << name;
72 }
73 }
74
75 delete driver->driver;
76 delete driver;
77 driver = nullptr;
78 }
79 }
80
81 inline yarp::dev::PolyDriver* drv() const
82 {
83 return driver->driver;
84 }
86 {
87 return &driver->runningThreads;
88 }
90 {
92 }
94 {
96 }
97
98 inline bool isValid() const
99 {
100 return drv()->isValid();
101 }
102 inline bool open()
103 {
105 return drv()->open(p);
106 }
107 inline bool close()
108 {
109 return drv()->close();
110 }
111
112 inline void registerThread(yarp::os::Thread* thread) const
113 {
114 reg_sem()->wait();
115 lst_sem()->wait();
116 thr()->push_back(thread);
117 reg_sem()->post();
118 lst_sem()->post();
119 }
120
121 inline void joinThreads() const
122 {
123 // The semafore will not allow other thread to be registered while
124 // joining threads.
125 // Other calls to joinThread() will stop at the semaphore and will
126 // be restarted as soon as all the threads are joined and the list
127 // is empty. This will avoid calling delete twice.
128 // stopThreads() must pass this semaphore, but in order to avoid to
129 // stop an already deleted thread we need a second semaphore.
130 reg_sem()->wait();
131 auto tit = thr()->begin();
132 while (tit != thr()->end()) {
133 yarp::os::Thread* thread = *tit;
134 thread->join();
135 lst_sem()->wait();
136 thr()->erase(tit++);
137 delete thread;
138 lst_sem()->post();
139 }
140 reg_sem()->post();
141 }
142
143 inline void stopThreads() const
144 {
145 lst_sem()->wait();
146 for (auto* thread : *thr()) {
147 thread->stop();
148 }
149 lst_sem()->post();
150 }
151
153 {
155
157 prop.put("device", type);
158 prop.put("id", name);
159
160 for (yarp::robotinterface::ParamList::const_iterator it = p.begin(); it != p.end(); ++it) {
161 const yarp::robotinterface::Param& param = *it;
162
163 // check if parentheses are balanced
164 std::string stringFormatValue = param.value();
165 int counter = 0;
166 for (size_t i = 0; i < stringFormatValue.size() && counter >= 0; i++) {
167 if (stringFormatValue[i] == '(') {
168 counter++;
169 } else if (stringFormatValue[i] == ')') {
170 counter--;
171 }
172 }
173 if (counter != 0) {
174 yCWarning(YRI_DEVICE) << "Parentheses not balanced for param " << param.name();
175 }
176
177 std::string s = "(" + param.name() + " " + param.value() + ")";
178 prop.fromString(s, false);
179 }
180
181 return prop;
182 }
183
184 std::string name;
185 std::string type;
189};
190
192{
193 dbg << "(name = \"" << t.name() << "\", type = \"" << t.type() << "\"";
194 if (!t.params().empty()) {
195 dbg << ", params = [";
196 dbg << t.params();
197 dbg << "]";
198 }
199 if (!t.actions().empty()) {
200 dbg << ", actions = [";
201 dbg << t.actions();
202 dbg << "]";
203 }
204 dbg << ")";
205 return dbg;
206}
207
209 mPriv(new Private(this))
210{
211 mPriv->close();
212}
213
215 const std::string& type,
217 const yarp::robotinterface::ActionList& actions) :
218 mPriv(new Private(this))
219{
220 mPriv->name = name;
221 mPriv->type = type;
222 mPriv->params = params;
223 mPriv->actions = actions;
224}
225
227 mPriv(new Private(*other.mPriv))
228{
229 mPriv->name = other.mPriv->name;
230 mPriv->type = other.mPriv->type;
231 mPriv->params = other.mPriv->params;
232 mPriv->actions = other.mPriv->actions;
233 *mPriv->driver = *other.mPriv->driver;
234}
235
237{
238 if (&other != this) {
239 mPriv->name = other.mPriv->name;
240 mPriv->type = other.mPriv->type;
241
242 mPriv->params.clear();
243 mPriv->params = other.mPriv->params;
244
245 mPriv->actions.clear();
246 mPriv->actions = other.mPriv->actions;
247
248 *mPriv->driver = *other.mPriv->driver;
249 }
250 return *this;
251}
252
254{
255 delete mPriv;
256}
257
259{
260 return mPriv->name;
261}
262
264{
265 return mPriv->type;
266}
267
272
277
278const std::string& yarp::robotinterface::Device::name() const
279{
280 return mPriv->name;
281}
282
283const std::string& yarp::robotinterface::Device::type() const
284{
285 return mPriv->type;
286}
287
289{
290 return mPriv->params;
291}
292
294{
295 return mPriv->actions;
296}
297
299{
300 if (mPriv->isValid()) {
301 yCError(YRI_DEVICE) << "Trying to open an already opened device.";
302 return false;
303 }
304
305 if (!mPriv->open()) {
306 yCWarning(YRI_DEVICE) << "Cannot open device" << mPriv->name;
307 return false;
308 }
309
310 return true;
311}
312
314{
315 if (!mPriv->isValid()) {
316 // Trying to close an already closed device. Perhaps open()
317 // Failed... Nothing to do and not worth sending an error.
318 return true;
319 }
320
321 if (!mPriv->close()) {
322 yCWarning(YRI_DEVICE) << "Cannot close device" << mPriv->name;
323 return false;
324 }
325
326 return true;
327}
328
329bool yarp::robotinterface::Device::hasParam(const std::string& name) const
330{
331 return yarp::robotinterface::hasParam(mPriv->params, name);
332}
333
334std::string yarp::robotinterface::Device::findParam(const std::string& name) const
335{
336 return yarp::robotinterface::findParam(mPriv->params, name);
337}
338
340{
341 return mPriv->drv();
342}
343
345{
346 mPriv->registerThread(thread);
347}
348
350{
351 mPriv->joinThreads();
352}
353
355{
356 mPriv->stopThreads();
357}
358
360{
361 if (!driver()) {
362 yCDebug(YRI_DEVICE) << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
363 return false;
364 }
365
366 yarp::dev::ICalibrator* calibrator;
367 if (!driver()->view(calibrator)) {
368 yCError(YRI_DEVICE) << name() << "is not a yarp::dev::ICalibrator, therefore it cannot have" << ActionTypeToString(ActionTypeCalibrate) << "actions";
369 return false;
370 }
371
372 yarp::dev::IControlCalibration* controlCalibrator;
373 if (!target.poly->view(controlCalibrator)) {
374 yCError(YRI_DEVICE) << target.key << "is not a yarp::dev::IControlCalibration2, therefore it cannot have" << ActionTypeToString(ActionTypeCalibrate) << "actions";
375 return false;
376 }
377
378 controlCalibrator->setCalibrator(calibrator);
379
380 // Saving pointer to Calibrator device into Wrapper to later use
381 // (NOTE this make sense if the target device is a controlBoard_nws_yarp, as it should be)
382 yarp::dev::IRemoteCalibrator* rem_calibrator_wrap;
383 yarp::dev::IRemoteCalibrator* rem_calibrator_calib;
384 bool rem_calibrator_available = true;
385
386 if (!target.poly->view(rem_calibrator_wrap)) {
387 yCWarning(YRI_DEVICE) << "Device " << target.key << "is not implementing a yarp::dev::IRemoteCalibrator, therefore it cannot attach to a Calibrator device. \n \
388 Please verify that the target of calibrate action is a controlBoard_nws_yarp device. \
389 This doesn't prevent the yarprobotinterface to correctly operate, but no remote calibration and homing will be available";
390 rem_calibrator_available = false;
391 }
392
393 if ((rem_calibrator_available) && (!driver()->view(rem_calibrator_calib))) {
394 yCWarning(YRI_DEVICE) << "Device " << name() << "is not implementing a yarp::dev::IRemoteCalibrator, therefore it cannot be used as a remote calibration device. \n \
395 This doesn't prevent the yarprobotinterface to correctly operate, but no remote calibration and homing will be available";
396 rem_calibrator_available = false;
397 }
398
399 if (rem_calibrator_available) {
400 rem_calibrator_wrap->setCalibratorDevice(rem_calibrator_calib);
401 }
402
403 // Start the calibrator thread
404 yarp::os::Thread* calibratorThread = new yarp::robotinterface::impl::CalibratorThread(calibrator,
405 name(),
406 target.poly,
407 target.key,
409 registerThread(calibratorThread);
410
411 if (!calibratorThread->start()) {
412 yCError(YRI_DEVICE) << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeCalibrate) << "on device" << target.key;
413 return false;
414 }
415
416 return true;
417}
418
420{
421 if (!driver()) {
422 yCDebug(YRI_DEVICE) << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
423 return false;
424 }
425
426 yarp::dev::IMultipleWrapper* multiplewrapper;
427 driver()->view(multiplewrapper);
428
429 if (drivers.size() == 1) {
430 yarp::dev::IWrapper* wrapper;
431 if (!driver()->view(wrapper)) {
432 // If the device is not a IWrapper, let's continue as we will try to call attachAll via IMultipleWrapper
433 yCDebug(YRI_DEVICE) << name() << "is not an IWrapper. Trying IMultipleWrapper";
434 } else if (wrapper->attach(drivers[0]->poly)) {
435 return true;
436 } else if (!multiplewrapper) {
437 yCError(YRI_DEVICE) << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeAttach);
438 return false;
439 } else {
440 yCInfo(YRI_DEVICE) << name() << "IWrapper::attach() failed. Trying IMultipleWrapper::attach().";
441 }
442 }
443
444 if (!multiplewrapper) {
445 yCError(YRI_DEVICE) << name() << "is not derived from IWrapper or IMultipleWrapper, therefore it cannot have" << ActionTypeToString(ActionTypeAttach) << "actions";
446 return false;
447 }
448
449 if (!multiplewrapper->attachAll(drivers)) {
450 yCError(YRI_DEVICE) << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeAttach);
451 return false;
452 }
453
454 return true;
455}
456
458{
459 if (!driver()) {
460 yCDebug(YRI_DEVICE) << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
461 return false;
462 }
463
464 yarp::dev::IWrapper* wrapper;
465 yarp::dev::IMultipleWrapper* multiplewrapper;
466 driver()->view(wrapper);
467 driver()->view(multiplewrapper);
468
469 if (!wrapper && !multiplewrapper) {
470 yCError(YRI_DEVICE) << name() << "is neither a wrapper nor a multiplewrapper, therefore it cannot have" << ActionTypeToString(ActionTypeDetach) << "actions";
471 return false;
472 }
473
474 if (multiplewrapper) {
475 if (multiplewrapper->detachAll()) {
476 return true;
477 }
478 if (!wrapper) {
479 yCError(YRI_DEVICE) << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeDetach);
480 return false;
481 }
482 yCInfo(YRI_DEVICE) << name() << "IMultipleWrapper::detachAll() failed. Trying IWrapper::detach().";
483 }
484
485 if (wrapper && !wrapper->detach()) {
486 yCError(YRI_DEVICE) << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeDetach);
487 return false;
488 }
489
490 return true;
491}
492
494{
495 yarp::dev::ICalibrator* calibrator;
496 if (!driver()) {
497 yCDebug(YRI_DEVICE) << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
498 return false;
499 }
500
501 if (!driver()->isValid()) {
502 yCError(YRI_DEVICE) << "park device do not exists";
503 return false;
504 }
505
506 if (!driver()->view(calibrator)) {
507 yCError(YRI_DEVICE) << name() << "is not a yarp::dev::ICalibrator, therefore it cannot have" << ActionTypeToString(ActionTypePark) << "actions";
508 return false;
509 }
510
511 yarp::dev::IControlCalibration* controlCalibrator;
512 if (!target.poly->view(controlCalibrator)) {
513 yCError(YRI_DEVICE) << target.key << "is not a yarp::dev::IControlCalibration2, therefore it cannot have" << ActionTypeToString(ActionTypePark) << "actions";
514 return false;
515 }
516
517 controlCalibrator->setCalibrator(calibrator); // TODO Check if this should be removed
518
520 name(),
521 target.poly,
522 target.key,
524 registerThread(parkerThread);
525
526 if (!parkerThread->start()) {
527 yCError(YRI_DEVICE) << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypePark) << "on device" << target.key;
528 return false;
529 }
530
531 return true;
532}
define control board standard interfaces
yarp::os::LogStream operator<<(yarp::os::LogStream dbg, const yarp::robotinterface::Device &t)
Definition Device.cpp:191
#define YARP_FIXME_NOTIMPLEMENTED(what)
Definition Log.h:411
bool view(T *&x)
Get an interface to the device driver.
Interface for a calibrator device.
Definition ICalibrator.h:21
Interface for control devices, calibration commands.
virtual bool setCalibrator(ICalibrator *c)
Set the calibrator object to be used to calibrate the robot.
Interface for an object that can wrap/attach to to another.
virtual bool detachAll()=0
Detach the object (you must have first called attach).
virtual bool attachAll(const PolyDriverList &drivers)=0
Attach to a list of objects.
IRemoteCalibrator interface is meant to remotize the access of the calibration device in order to all...
virtual bool setCalibratorDevice(yarp::dev::IRemoteCalibrator *dev)
setCalibratorDevice: store the pointer to the calibrator device.
Interface for an object that can wrap/or "attach" to another.
Definition IWrapper.h:25
virtual bool detach()=0
Detach the object (you must have first called attach).
virtual bool attach(PolyDriver *driver)=0
Attach to another object.
A container for a device driver.
Definition PolyDriver.h:23
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 class for storing options and configuration information.
Definition Property.h:33
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
A class for thread synchronization and mutual exclusion.
Definition Semaphore.h:25
void wait()
Decrement the counter, even if we must wait to do that.
Definition Semaphore.cpp:96
void post()
Increment the counter.
An abstraction for a thread of execution.
Definition Thread.h:21
bool join(double seconds=-1)
The function returns when the thread execution has completed.
Definition Thread.cpp:76
bool start()
Start the new thread running.
Definition Thread.cpp:93
Private & operator=(const Private &other)
Definition Device.cpp:57
yarp::os::Semaphore * reg_sem() const
Definition Device.cpp:89
yarp::dev::PolyDriver * drv() const
Definition Device.cpp:81
Private(const Private &other)
Definition Device.cpp:51
yarp::os::Property paramsAsProperty() const
Definition Device.cpp:152
yarp::os::Semaphore * lst_sem() const
Definition Device.cpp:93
void registerThread(yarp::os::Thread *thread) const
Definition Device.cpp:112
yarp::robotinterface::ThreadList * thr() const
Definition Device.cpp:85
bool attach(const yarp::dev::PolyDriverList &drivers) const
Definition Device.cpp:419
bool park(const yarp::dev::PolyDriverDescriptor &target) const
Definition Device.cpp:493
yarp::dev::PolyDriver * driver() const
Definition Device.cpp:339
bool hasParam(const std::string &name) const
Definition Device.cpp:329
bool calibrate(const yarp::dev::PolyDriverDescriptor &target) const
Definition Device.cpp:359
Device & operator=(const Device &other)
Definition Device.cpp:236
std::string findParam(const std::string &name) const
Definition Device.cpp:334
void registerThread(yarp::os::Thread *thread) const
Definition Device.cpp:344
std::string & name()
Definition Param.cpp:83
std::string & value()
Definition Param.cpp:88
#define yCInfo(component,...)
#define yCError(component,...)
#define yCWarning(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
robotinterface::ParamList mergeDuplicateGroups(const robotinterface::ParamList &list)
Definition Types.cpp:62
std::vector< robotinterface::Action > ActionList
Definition Types.h:31
std::string ActionTypeToString(robotinterface::ActionType actiontype)
Definition Types.cpp:151
bool hasParam(const robotinterface::ParamList &list, const std::string &name)
Definition Types.cpp:20
std::vector< robotinterface::Param > ParamList
Definition Types.h:30
std::string findParam(const robotinterface::ParamList &list, const std::string &name)
Definition Types.cpp:30
std::list< yarp::os::Thread * > ThreadList
Definition Types.h:33
The main, catch-all namespace for YARP.
Definition dirs.h:16
#define YARP_UNUSED(var)
Definition api.h:162