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