YARP
Yet Another Robot Platform
Device.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
10 
14 
15 #include <yarp/os/LogStream.h>
16 #include <yarp/os/Property.h>
17 #include <yarp/os/Semaphore.h>
18 
22 #include <yarp/dev/IWrapper.h>
23 #include <yarp/dev/PolyDriver.h>
24 
25 #include <string>
26 
27 
29 {
30 
31 public:
32  struct Driver
33  {
35  driver(d),
36  ref(1)
37  {
38  }
43  int ref;
44  };
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) {
67  stopThreads();
68 
69  if (driver->driver->isValid()) {
70  if (!driver->driver->close()) {
71  yWarning() << "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  }
89  inline yarp::os::Semaphore* reg_sem() const
90  {
92  }
93  inline yarp::os::Semaphore* lst_sem() const
94  {
95  return &driver->threadListSemaphore;
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 
156  yarp::os::Property prop;
157  prop.put("device", type);
158 
159  for (yarp::robotinterface::experimental::ParamList::const_iterator it = p.begin(); it != p.end(); ++it) {
161 
162  // check if parentheses are balanced
163  std::string stringFormatValue = param.value();
164  int counter = 0;
165  for (size_t i = 0; i < stringFormatValue.size() && counter >= 0; i++) {
166  if (stringFormatValue[i] == '(') {
167  counter++;
168  } else if (stringFormatValue[i] == ')') {
169  counter--;
170  }
171  }
172  if (counter != 0) {
173  yWarning() << "Parentheses not balanced for param " << param.name();
174  }
175 
176  std::string s = "(" + param.name() + " " + param.value() + ")";
177  prop.fromString(s, false);
178  }
179 
180  return prop;
181  }
182 
183  std::string name;
184  std::string type;
188 };
189 
190 std::ostream& std::operator<<(std::ostream& oss, const yarp::robotinterface::experimental::Device& t)
191 {
192  oss << "(name = \"" << t.name() << "\", type = \"" << t.type() << "\"";
193  if (!t.params().empty()) {
194  oss << ", params = [";
195  oss << t.params();
196  oss << "]";
197  }
198  if (!t.actions().empty()) {
199  oss << ", actions = [";
200  oss << t.actions();
201  oss << "]";
202  }
203  oss << ")";
204  return oss;
205 }
206 
208 {
209  std::ostringstream oss;
210  oss << t;
211  dbg << oss.str();
212  return dbg;
213 }
214 
216  mPriv(new Private(this))
217 {
218  mPriv->close();
219 }
220 
222  const std::string& type,
225  mPriv(new Private(this))
226 {
227  mPriv->name = name;
228  mPriv->type = type;
229  mPriv->params = params;
230  mPriv->actions = actions;
231 }
232 
234  mPriv(new Private(*other.mPriv))
235 {
236  mPriv->name = other.mPriv->name;
237  mPriv->type = other.mPriv->type;
238  mPriv->params = other.mPriv->params;
239  mPriv->actions = other.mPriv->actions;
240  *mPriv->driver = *other.mPriv->driver;
241 }
242 
244 {
245  if (&other != this) {
246  mPriv->name = other.mPriv->name;
247  mPriv->type = other.mPriv->type;
248 
249  mPriv->params.clear();
250  mPriv->params = other.mPriv->params;
251 
252  mPriv->actions.clear();
253  mPriv->actions = other.mPriv->actions;
254 
255  *mPriv->driver = *other.mPriv->driver;
256  }
257  return *this;
258 }
259 
261 {
262  delete mPriv;
263 }
264 
266 {
267  return mPriv->name;
268 }
269 
271 {
272  return mPriv->type;
273 }
274 
276 {
277  return mPriv->params;
278 }
279 
281 {
282  return mPriv->actions;
283 }
284 
286 {
287  return mPriv->name;
288 }
289 
291 {
292  return mPriv->type;
293 }
294 
296 {
297  return mPriv->params;
298 }
299 
301 {
302  return mPriv->actions;
303 }
304 
306 {
307  if (mPriv->isValid()) {
308  yError() << "Trying to open an already opened device.";
309  return false;
310  }
311 
312  if (!mPriv->open()) {
313  yWarning() << "Cannot open device" << mPriv->name;
314  return false;
315  }
316 
317  return true;
318 }
319 
321 {
322  if (!mPriv->isValid()) {
323  // Trying to close an already closed device. Perhaps open()
324  // Failed... Nothing to do and not worth sending an error.
325  return true;
326  }
327 
328  if (!mPriv->close()) {
329  yWarning() << "Cannot close device" << mPriv->name;
330  return false;
331  }
332 
333  return true;
334 }
335 
336 bool yarp::robotinterface::experimental::Device::hasParam(const std::string& name) const
337 {
338  return yarp::robotinterface::experimental::hasParam(mPriv->params, name);
339 }
340 
341 std::string yarp::robotinterface::experimental::Device::findParam(const std::string& name) const
342 {
343  return yarp::robotinterface::experimental::findParam(mPriv->params, name);
344 }
345 
347 {
348  return mPriv->drv();
349 }
350 
352 {
353  mPriv->registerThread(thread);
354 }
355 
357 {
358  mPriv->joinThreads();
359 }
360 
362 {
363  mPriv->stopThreads();
364 }
365 
367 {
368  if (!driver()) {
369  yDebug() << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
370  return false;
371  }
372 
373  yarp::dev::ICalibrator* calibrator;
374  if (!driver()->view(calibrator)) {
375  yError() << name() << "is not a yarp::dev::ICalibrator, therefore it cannot have" << ActionTypeToString(ActionTypeCalibrate) << "actions";
376  return false;
377  }
378 
379  yarp::dev::IControlCalibration* controlCalibrator;
380  if (!target.poly->view(controlCalibrator)) {
381  yError() << target.key << "is not a yarp::dev::IControlCalibration2, therefore it cannot have" << ActionTypeToString(ActionTypeCalibrate) << "actions";
382  return false;
383  }
384 
385  controlCalibrator->setCalibrator(calibrator);
386 
387  // Saving pointer to Calibrator device into Wrapper to later use
388  // (NOTE this make sense if the target device is a controlboardwrapper2, as it should be)
389  yarp::dev::IRemoteCalibrator* rem_calibrator_wrap;
390  yarp::dev::IRemoteCalibrator* rem_calibrator_calib;
391  bool rem_calibrator_available = true;
392 
393  if (!target.poly->view(rem_calibrator_wrap)) {
394  yWarning() << "Device " << target.key << "is not implementing a yarp::dev::IRemoteCalibrator, therefore it cannot attach to a Calibrator device. \n \
395  Please verify that the target of calibrate action is a controlboardwrapper2 device. \
396  This doesn't prevent the yarprobotinterface to correctly operate, but no remote calibration and homing will be available";
397  rem_calibrator_available = false;
398  }
399 
400  if ((rem_calibrator_available) && (!driver()->view(rem_calibrator_calib))) {
401  yWarning() << "Device " << name() << "is not implementing a yarp::dev::IRemoteCalibrator, therefore it cannot be used as a remote calibration device. \n \
402  This doesn't prevent the yarprobotinterface to correctly operate, but no remote calibration and homing will be available";
403  rem_calibrator_available = false;
404  }
405 
406  if (rem_calibrator_available)
407  rem_calibrator_wrap->setCalibratorDevice(rem_calibrator_calib);
408 
409  // Start the calibrator thread
410  yarp::os::Thread* calibratorThread = new yarp::robotinterface::impl::CalibratorThread(calibrator,
411  name(),
412  target.poly,
413  target.key,
415  registerThread(calibratorThread);
416 
417  if (!calibratorThread->start()) {
418  yError() << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeCalibrate) << "on device" << target.key;
419  return false;
420  }
421 
422  return true;
423 }
424 
426 {
427  if (!driver()) {
428  yDebug() << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
429  return false;
430  }
431 
432  yarp::dev::IMultipleWrapper* multiplewrapper;
433  driver()->view(multiplewrapper);
434 
435  if (drivers.size() == 1) {
436  yarp::dev::IWrapper* wrapper;
437  if (!driver()->view(wrapper)) {
438  yInfo() << name() << "is not an IWrapper. Trying IMultipleWrapper";
439  } else if (wrapper->attach(drivers[0]->poly)) {
440  return true;
441  } else if (!multiplewrapper) {
442  yError() << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeAttach);
443  return false;
444  } else {
445  yInfo() << name() << "IWrapper::attach() failed. Trying IMultipleWrapper::attach().";
446  }
447  }
448 
449  if (!multiplewrapper) {
450  yError() << name() << "is not a multiplewrapper, therefore it cannot have" << ActionTypeToString(ActionTypeAttach) << "actions";
451  return false;
452  }
453 
454  if (!multiplewrapper->attachAll(drivers)) {
455  yError() << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeAttach);
456  return false;
457  }
458 
459  return true;
460 }
461 
463 {
464  if (!driver()) {
465  yDebug() << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
466  return false;
467  }
468 
469  yarp::dev::IWrapper* wrapper;
470  yarp::dev::IMultipleWrapper* multiplewrapper;
471  driver()->view(wrapper);
472  driver()->view(multiplewrapper);
473 
474  if (!wrapper && !multiplewrapper) {
475  yError() << name() << "is neither a wrapper nor a multiplewrapper, therefore it cannot have" << ActionTypeToString(ActionTypeDetach) << "actions";
476  return false;
477  }
478 
479  if (multiplewrapper) {
480  if (multiplewrapper->detachAll()) {
481  return true;
482  }
483  if (!wrapper) {
484  yError() << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeDetach);
485  return false;
486  }
487  yInfo() << name() << "IMultipleWrapper::detachAll() failed. Trying IWrapper::detach().";
488  }
489 
490  if (wrapper && !wrapper->detach()) {
491  yError() << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypeDetach);
492  return false;
493  }
494 
495  return true;
496 }
497 
499 {
500  yarp::dev::ICalibrator* calibrator;
501  if (!driver()) {
502  yDebug() << "Device do not exists, cannot do " << ActionTypeToString(ActionTypeDetach) << "action";
503  return false;
504  }
505 
506  if (!driver()->isValid()) {
507  yError() << "park device do not exists";
508  return false;
509  }
510 
511  if (!driver()->view(calibrator)) {
512  yError() << name() << "is not a yarp::dev::ICalibrator, therefore it cannot have" << ActionTypeToString(ActionTypePark) << "actions";
513  return false;
514  }
515 
516  yarp::dev::IControlCalibration* controlCalibrator;
517  if (!target.poly->view(controlCalibrator)) {
518  yError() << target.key << "is not a yarp::dev::IControlCalibration2, therefore it cannot have" << ActionTypeToString(ActionTypePark) << "actions";
519  return false;
520  }
521 
522  controlCalibrator->setCalibrator(calibrator); // TODO Check if this should be removed
523 
524  yarp::os::Thread* parkerThread = new yarp::robotinterface::impl::CalibratorThread(calibrator,
525  name(),
526  target.poly,
527  target.key,
529  registerThread(parkerThread);
530 
531  if (!parkerThread->start()) {
532  yError() << "Device" << name() << "cannot execute" << ActionTypeToString(ActionTypePark) << "on device" << target.key;
533  return false;
534  }
535 
536  return true;
537 }
define control board standard interfaces
yarp::os::LogStream operator<<(yarp::os::LogStream dbg, const yarp::robotinterface::experimental::Device &t)
Definition: Device.cpp:207
float t
#define yInfo(...)
Definition: Log.h:260
#define yError(...)
Definition: Log.h:282
#define YARP_FIXME_NOTIMPLEMENTED(what)
Definition: Log.h:310
#define yDebug(...)
Definition: Log.h:237
#define yWarning(...)
Definition: Log.h:271
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:77
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 attachAll(const PolyDriverList &p)=0
Attach to a list of objects.
virtual bool detachAll()=0
Detach the object (you must have first called attach).
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:29
virtual bool detach()=0
Detach the object (you must have first called attach).
virtual bool attach(PolyDriver *poly)=0
Attach to another object.
A container for a device driver.
Definition: PolyDriver.h:27
bool close() override
Close the DeviceDriver.
Definition: PolyDriver.cpp:176
bool isValid() const
Check if device is valid.
Definition: PolyDriver.cpp:199
bool open(const std::string &txt)
Construct and configure a device by its common name.
Definition: PolyDriver.cpp:143
A class for storing options and configuration information.
Definition: Property.h:37
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1046
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:998
A class for thread synchronization and mutual exclusion.
Definition: Semaphore.h:29
void wait()
Decrement the counter, even if we must wait to do that.
Definition: Semaphore.cpp:99
void post()
Increment the counter.
Definition: Semaphore.cpp:114
An abstraction for a thread of execution.
Definition: Thread.h:25
bool join(double seconds=-1)
The function returns when the thread execution has completed.
Definition: Thread.cpp:79
bool start()
Start the new thread running.
Definition: Thread.cpp:96
yarp::robotinterface::experimental::ThreadList * thr() const
Definition: Device.cpp:85
yarp::os::Semaphore * reg_sem() const
Definition: Device.cpp:89
yarp::os::Semaphore * lst_sem() const
Definition: Device.cpp:93
void registerThread(yarp::os::Thread *thread) const
Definition: Device.cpp:112
Private & operator=(const Private &other)
Definition: Device.cpp:57
yarp::dev::PolyDriver * drv() const
Definition: Device.cpp:81
bool attach(const yarp::dev::PolyDriverList &drivers) const
Definition: Device.cpp:425
yarp::dev::PolyDriver * driver() const
Definition: Device.cpp:346
bool hasParam(const std::string &name) const
Definition: Device.cpp:336
Device & operator=(const Device &other)
Definition: Device.cpp:243
bool calibrate(const yarp::dev::PolyDriverDescriptor &target) const
Definition: Device.cpp:366
bool park(const yarp::dev::PolyDriverDescriptor &target) const
Definition: Device.cpp:498
std::string findParam(const std::string &name) const
Definition: Device.cpp:341
void registerThread(yarp::os::Thread *thread) const
Definition: Device.cpp:351
bool isValid()
Check if time is valid (non-zero).
Definition: Time.cpp:317
std::string findParam(const robotinterface::experimental::ParamList &list, const std::string &name)
Definition: Types.cpp:29
robotinterface::experimental::ParamList mergeDuplicateGroups(const robotinterface::experimental::ParamList &list)
Definition: Types.cpp:61
bool hasParam(const robotinterface::experimental::ParamList &list, const std::string &name)
Definition: Types.cpp:19
std::vector< robotinterface::experimental::Action > ActionList
Definition: Types.h:35
std::string ActionTypeToString(robotinterface::experimental::ActionType actiontype)
Definition: Types.cpp:149
std::vector< robotinterface::experimental::Param > ParamList
Definition: Types.h:32
std::list< yarp::os::Thread * > ThreadList
Definition: Types.h:37
The main, catch-all namespace for YARP.
Definition: environment.h:18
#define YARP_UNUSED(var)
Definition: api.h:159