yarp-devices
DeviceMapper.hpp
1 // -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
2 
3 #ifndef __DEVICE_MAPPER_HPP__
4 #define __DEVICE_MAPPER_HPP__
5 
6 #include <cstdlib> // std::size_t
7 
8 #include <functional> // std::invoke
9 #include <memory>
10 #include <tuple>
11 #include <typeindex>
12 #include <unordered_map>
13 #include <vector>
14 
15 #include <yarp/dev/PolyDriver.h>
16 
17 #include "FutureTask.hpp"
18 #include "RawDevice.hpp"
19 
20 namespace roboticslab
21 {
22 
64 class DeviceMapper final
65 {
66 public:
68  DeviceMapper();
69 
71  ~DeviceMapper();
72 
74  void enableParallelization(unsigned int concurrentTasks);
75 
77  bool registerDevice(yarp::dev::PolyDriver * driver);
78 
80  void clear();
81 
83  std::unique_ptr<FutureTask> createTask() const
84  { return taskFactory->createTask(); }
85 
87  using dev_index_t = std::tuple<const RawDevice *, int>;
88 
90  using dev_group_t = std::tuple<const RawDevice *, std::vector<int>, int>;
91 
96  const std::vector<std::unique_ptr<const RawDevice>> & getDevices() const
97  { return devices; }
98 
108  dev_index_t getMotorDevice(int globalAxis) const;
109 
117  std::vector<dev_index_t> getMotorDevicesWithOffsets() const;
118 
127  std::vector<dev_group_t> getMotorDevicesWithIndices(int globalAxesCount, const int * globalAxes) const;
128 
130  int getControlledAxes() const
131  { return totalAxes; }
132 
134  template<typename T, typename... T_ref>
135  using motor_single_joint_fn = bool (T::*)(int, T_ref...);
136 
138  template<typename T, typename... T_ref>
140  {
141  auto [device, offset] = getMotorDevice(j);
142  T * p = device->getHandle<T>();
143  return p ? std::invoke(fn, p, offset, ref...) : false;
144  }
145 
147  template<typename T, typename... T_refs>
148  using motor_all_joints_fn = bool (T::*)(T_refs *...);
149 
151  template<typename T, typename... T_refs>
153  {
154  auto task = createTask();
155  bool ok = false;
156 
157  for (const auto & [device, offset] : getMotorDevicesWithOffsets())
158  {
159  T * p = device->template getHandle<T>();
160  ok |= p && (task->add(p, fn, refs + offset...), true);
161  }
162 
163  // at least one targeted device must implement the 'T' iface
164  return ok && task->dispatch();
165  }
166 
168  template<typename T, typename... T_refs>
169  using motor_multi_joints_fn = bool (T::*)(int, const int *, T_refs *...);
170 
172  template<typename T, typename... T_refs>
173  bool mapJointGroup(motor_multi_joints_fn<T, T_refs...> fn, int n_joint, const int * joints, T_refs *... refs)
174  {
175  auto task = createTask();
176  auto devices = getMotorDevicesWithIndices(n_joint, joints); // extend lifetime of vector of local indices
177  bool ok = true;
178 
179  for (const auto & [device, localIndices, globalIndex] : devices)
180  {
181  T * p = device->template getHandle<T>();
182  ok &= p && (task->add(p, fn, localIndices.size(), localIndices.data(), refs + globalIndex...), true);
183  }
184 
185  // all targeted devices must implement the 'T' iface
186  return ok && task->dispatch();
187  }
188 
190  template<typename T>
192  {
193  // operator[] will insert a default-constructed value if not found
194  if (auto it = connectedSensors.find(typeid(T)); it != connectedSensors.cend())
195  {
196  return it->second;
197  }
198 
199  return 0;
200  }
201 
208  template<typename T>
209  dev_index_t getSensorDevice(int globalIndex) const
210  {
211  if (auto it = sensorOffsets.find(typeid(T)); it != sensorOffsets.cend())
212  {
213  const auto & [deviceIndex, offset, count] = it->second[globalIndex];
214  return {devices[deviceIndex].get(), globalIndex - offset};
215  }
216 
217  return {&invalidDevice, 0};
218  }
219 
220  template<typename T, typename T_out>
221  using sensor_status_fn = T_out (T::*)(std::size_t) const;
222 
227  template<typename T, typename T_out>
228  T_out getSensorStatus(sensor_status_fn<T, T_out> fn, std::size_t index) const
229  {
230  auto [device, offset] = getSensorDevice<T>(index);
231  T * p = device->template getHandle<T>();
232  return p ? std::invoke(fn, p, offset) : static_cast<T_out>(DeviceMapper::getSensorFailureStatus());
233  }
234 
235  template<typename T>
236  using sensor_size_fn = std::size_t (T::*)(std::size_t) const;
237 
242  template<typename T>
243  std::size_t getSensorArraySize(sensor_size_fn<T> fn, std::size_t index) const
244  {
245  auto [device, offset] = getSensorDevice<T>(index);
246  T * p = device->template getHandle<T>();
247  return p ? std::invoke(fn, p, offset) : 0;
248  }
249 
250  template<typename T, typename... T_out_params>
251  using sensor_output_fn = bool (T::*)(std::size_t, T_out_params &...) const;
252 
257  template<typename T, typename... T_out_params>
258  bool getSensorOutput(sensor_output_fn<T, T_out_params...> fn, std::size_t index, T_out_params &... params) const
259  {
260  auto [device, offset] = getSensorDevice<T>(index);
261  T * p = device->template getHandle<T>();
262  return p ? std::invoke(fn, p, offset, params...) : false;
263  }
264 
265 private:
266  static const int getSensorFailureStatus();
267 
268  using dev_index_offset_t = std::tuple<int, int, int>;
269 
270  std::vector<std::unique_ptr<const RawDevice>> devices;
271  std::vector<dev_index_offset_t> motorOffsets;
272  std::unordered_map<std::type_index, std::vector<dev_index_offset_t>> sensorOffsets;
273  std::unordered_map<std::type_index, int> connectedSensors;
274 
275  int totalAxes {0};
276 
277  std::unique_ptr<FutureTaskFactory> taskFactory;
278 };
279 
280 } // namespace roboticslab
281 
282 #endif // __DEVICE_MAPPER_HPP__
Exposes raw subdevice interface handles on a per-axis manner.
Definition: DeviceMapper.hpp:65
const std::vector< std::unique_ptr< const RawDevice > > & getDevices() const
Retrieve all registered raw devices, regardless of type.
Definition: DeviceMapper.hpp:96
std::vector< dev_index_t > getMotorDevicesWithOffsets() const
Retrieve all registered motor subdevices and their associated offsets.
Definition: DeviceMapper.cpp:166
std::tuple< const RawDevice *, std::vector< int >, int > dev_group_t
Tuple of a raw device pointer, its local indices and the global index.
Definition: DeviceMapper.hpp:90
std::tuple< const RawDevice *, int > dev_index_t
Tuple of a raw device pointer and either an offset or a local index.
Definition: DeviceMapper.hpp:87
bool(T::*)(T_refs *...) motor_all_joints_fn
Alias for a full-joint command. See class description.
Definition: DeviceMapper.hpp:148
int getConnectedSensors() const
Retrieve the number of connected sensors of the specified type across all subdevices.
Definition: DeviceMapper.hpp:191
std::size_t getSensorArraySize(sensor_size_fn< T > fn, std::size_t index) const
Retrieve the size of the sensor array at the specified global index.
Definition: DeviceMapper.hpp:243
DeviceMapper()
Constructor.
Definition: DeviceMapper.cpp:110
void enableParallelization(unsigned int concurrentTasks)
Whether to enable parallel mappings and on how many concurrent threads.
Definition: DeviceMapper.cpp:119
bool(T::*)(int, T_ref...) motor_single_joint_fn
Alias for a single-joint command. See class description.
Definition: DeviceMapper.hpp:135
dev_index_t getSensorDevice(int globalIndex) const
Retrieve a sensor device handle and its local index given a global index.
Definition: DeviceMapper.hpp:209
void clear()
Delete all internal handles.
Definition: DeviceMapper.cpp:205
bool registerDevice(yarp::dev::PolyDriver *driver)
Extract interface handles and perform sanity checks.
Definition: DeviceMapper.cpp:124
std::unique_ptr< FutureTask > createTask() const
Create an instance of a deferred task.
Definition: DeviceMapper.hpp:83
~DeviceMapper()
Destructor.
Definition: DeviceMapper.cpp:114
T_out getSensorStatus(sensor_status_fn< T, T_out > fn, std::size_t index) const
Retrieve the status of the sensor device at the specified global index.
Definition: DeviceMapper.hpp:228
std::vector< dev_group_t > getMotorDevicesWithIndices(int globalAxesCount, const int *globalAxes) const
Retrieve motor subdevices that map to the specified global axes.
Definition: DeviceMapper.cpp:180
int getControlledAxes() const
Retrieve the number of controlled axes across all subdevices.
Definition: DeviceMapper.hpp:130
bool(T::*)(int, const int *, T_refs *...) motor_multi_joints_fn
Alias for a joint-group command. See class description.
Definition: DeviceMapper.hpp:169
bool mapSingleJoint(motor_single_joint_fn< T, T_ref... > fn, int j, T_ref... ref)
Single-joint command mapping. See class description.
Definition: DeviceMapper.hpp:139
bool mapJointGroup(motor_multi_joints_fn< T, T_refs... > fn, int n_joint, const int *joints, T_refs *... refs)
Joint-group command mapping. See class description.
Definition: DeviceMapper.hpp:173
bool mapAllJoints(motor_all_joints_fn< T, T_refs... > fn, T_refs *... refs)
Full-joint command mapping. See class description.
Definition: DeviceMapper.hpp:152
dev_index_t getMotorDevice(int globalAxis) const
Retrieve a motor device handle and its local index given a global index.
Definition: DeviceMapper.cpp:160
bool getSensorOutput(sensor_output_fn< T, T_out_params... > fn, std::size_t index, T_out_params &... params) const
Retrieve information from the sensor device at the specified global index.
Definition: DeviceMapper.hpp:258
The main, catch-all namespace for Robotics Lab UC3M.
Definition: groups.dox:6
const RawDevice invalidDevice(nullptr)
Singleton instance for an invalid (empty) raw device.