Skip to content

Commit 72b1dc6

Browse files
authored
[HardwareComponentInterface] Add get state and command interface handle methods (#2831)
1 parent 47d562a commit 72b1dc6

File tree

2 files changed

+283
-62
lines changed

2 files changed

+283
-62
lines changed

hardware_interface/include/hardware_interface/handle.hpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,61 @@ class Handle
243243
// END
244244
}
245245

246+
/**
247+
* @brief Get the value of the handle.
248+
* @tparam T The type of the value to be retrieved.
249+
* @param value The variable to store the retrieved value.
250+
* @param wait_for_lock If true, the method will wait for the lock to be available, else it will
251+
* try to get the lock without blocking.
252+
* @return true if the value is retrieved successfully, false otherwise.
253+
*
254+
* @note The method is thread-safe.
255+
* @note This method is real-time safe or non-blocking, only if wait_for_lock is set to false.
256+
* @note Ideal for the data types that are large in size to avoid copy during return.
257+
*/
258+
template <
259+
typename T, typename = std::enable_if_t<
260+
!std::is_same_v<std::decay_t<T>, std::shared_lock<std::shared_mutex>>>>
261+
[[nodiscard]] bool get_value(T & value, bool wait_for_lock) const
262+
{
263+
if (wait_for_lock)
264+
{
265+
std::shared_lock<std::shared_mutex> lock(handle_mutex_);
266+
return get_value(lock, value);
267+
}
268+
else
269+
{
270+
std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
271+
return get_value(lock, value);
272+
}
273+
}
274+
275+
/**
276+
* @brief Set the value of the handle.
277+
* @tparam T The type of the value to be set.
278+
* @param value The value to be set.
279+
* @param wait_for_lock If true, the method will wait for the lock to be available, else it will
280+
* try to get the lock without blocking.
281+
* @return true if the value is set successfully, false otherwise.
282+
*
283+
* @note The method is thread-safe.
284+
* @note This method is real-time safe or non-blocking, only if wait_for_lock is set to false.
285+
*/
286+
template <typename T>
287+
[[nodiscard]] bool set_value(const T & value, bool wait_for_lock)
288+
{
289+
if (wait_for_lock)
290+
{
291+
std::unique_lock<std::shared_mutex> lock(handle_mutex_);
292+
return set_value(lock, value);
293+
}
294+
else
295+
{
296+
std::unique_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
297+
return set_value(lock, value);
298+
}
299+
}
300+
246301
/**
247302
* @brief Set the value of the handle.
248303
* @tparam T The type of the value to be set.
@@ -315,6 +370,68 @@ class Handle
315370
return (value_ptr_ != nullptr) || !std::holds_alternative<std::monostate>(value_);
316371
}
317372

373+
protected:
374+
/**
375+
* @brief Get the value of the handle.
376+
* @tparam T The type of the value to be retrieved.
377+
* @param lock The lock to access the value.
378+
* @param value The variable to store the retrieved value.
379+
* @return true if the value is retrieved successfully, false otherwise.
380+
* @note The method is thread-safe and non-blocking.
381+
* @note Ideal for the data types that are large in size to avoid copy during return.
382+
*/
383+
template <typename T>
384+
[[nodiscard]] bool get_value(std::shared_lock<std::shared_mutex> & lock, T & value) const
385+
{
386+
if (!lock.owns_lock())
387+
{
388+
return false;
389+
}
390+
// BEGIN (Handle export change): for backward compatibility
391+
// TODO(saikishor) get value_ if old functionality is removed
392+
if constexpr (std::is_same_v<T, double>)
393+
{
394+
switch (data_type_)
395+
{
396+
case HandleDataType::DOUBLE:
397+
THROW_ON_NULLPTR(value_ptr_);
398+
value = *value_ptr_;
399+
return true;
400+
case HandleDataType::BOOL:
401+
// TODO(christophfroehlich): replace with RCLCPP_WARN_ONCE once
402+
// https://github.com/ros2/rclcpp/issues/2587
403+
// is fixed
404+
if (!notified_)
405+
{
406+
RCLCPP_WARN(
407+
rclcpp::get_logger(get_name()),
408+
"Casting bool to double for interface: %s. Better use get_optional<bool>().",
409+
get_name().c_str());
410+
notified_ = true;
411+
}
412+
value = static_cast<double>(std::get<bool>(value_));
413+
return true;
414+
default:
415+
throw std::runtime_error(
416+
fmt::format(
417+
FMT_COMPILE("Data type: '{}' cannot be casted to double for interface: {}"),
418+
data_type_.to_string(), get_name()));
419+
}
420+
}
421+
try
422+
{
423+
value = std::get<T>(value_);
424+
return true;
425+
}
426+
catch (const std::bad_variant_access & err)
427+
{
428+
throw std::runtime_error(
429+
fmt::format(
430+
FMT_COMPILE("Invalid data type: '{}' access for interface: {} expected: '{}'"),
431+
get_type_name<T>(), get_name(), data_type_.to_string()));
432+
}
433+
}
434+
318435
private:
319436
void copy(const Handle & other) noexcept
320437
{

0 commit comments

Comments
 (0)