75 [[deprecated(
"Use InterfaceDescription for initializing the Interface")]]
76 Handle(
const std::string & prefix_name,
const std::string & interface_name,
double * value_ptr)
78 interface_name_(interface_name),
85 const std::string & prefix_name,
const std::string & interface_name,
86 const std::string & data_type =
"double",
const std::string & initial_value =
"")
88 interface_name_(interface_name),
93 if (data_type_ == hardware_interface::HandleDataType::DOUBLE)
97 value_ = initial_value.empty() ? std::numeric_limits<double>::quiet_NaN()
99 value_ptr_ = std::get_if<double>(&value_);
101 catch (
const std::invalid_argument & err)
103 throw std::invalid_argument(
105 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
106 initial_value, handle_name_, data_type_.to_string()));
109 else if (data_type_ == hardware_interface::HandleDataType::FLOAT32)
113 value_ptr_ =
nullptr;
114 value_ = initial_value.empty()
115 ? std::numeric_limits<float>::quiet_NaN()
118 catch (
const std::invalid_argument & err)
120 throw std::invalid_argument(
122 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
123 initial_value, handle_name_, data_type_.to_string()));
126 else if (data_type_ == hardware_interface::HandleDataType::BOOL)
130 value_ptr_ =
nullptr;
133 catch (
const std::invalid_argument & err)
135 throw std::invalid_argument(
137 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
138 initial_value, handle_name_, data_type_.to_string()));
141 else if (data_type_ == hardware_interface::HandleDataType::UINT8)
145 value_ptr_ =
nullptr;
146 value_ = initial_value.empty()
147 ?
static_cast<uint8_t
>(std::numeric_limits<uint8_t>::max())
148 :
static_cast<uint8_t
>(hardware_interface::stoui8(initial_value));
150 catch (
const std::invalid_argument & err)
152 throw std::invalid_argument(
154 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
155 initial_value, handle_name_, data_type_.to_string()));
158 else if (data_type_ == hardware_interface::HandleDataType::INT8)
162 value_ptr_ =
nullptr;
163 value_ = initial_value.empty()
164 ?
static_cast<int8_t
>(std::numeric_limits<int8_t>::max())
165 :
static_cast<int8_t
>(hardware_interface::stoi8(initial_value));
167 catch (
const std::invalid_argument & err)
169 throw std::invalid_argument(
171 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
172 initial_value, handle_name_, data_type_.to_string()));
175 else if (data_type_ == hardware_interface::HandleDataType::UINT16)
179 value_ptr_ =
nullptr;
180 value_ = initial_value.empty()
181 ?
static_cast<uint16_t
>(std::numeric_limits<uint16_t>::max())
182 :
static_cast<uint16_t
>(hardware_interface::stoui16(initial_value));
184 catch (
const std::invalid_argument & err)
186 throw std::invalid_argument(
188 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
189 initial_value, handle_name_, data_type_.to_string()));
192 else if (data_type_ == hardware_interface::HandleDataType::INT16)
196 value_ptr_ =
nullptr;
197 value_ = initial_value.empty()
198 ?
static_cast<int16_t
>(std::numeric_limits<int16_t>::max())
199 :
static_cast<int16_t
>(hardware_interface::stoi16(initial_value));
201 catch (
const std::invalid_argument & err)
203 throw std::invalid_argument(
205 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
206 initial_value, handle_name_, data_type_.to_string()));
209 else if (data_type_ == hardware_interface::HandleDataType::UINT32)
213 value_ptr_ =
nullptr;
214 value_ = initial_value.empty()
215 ?
static_cast<uint32_t
>(std::numeric_limits<uint32_t>::max())
216 :
static_cast<uint32_t
>(hardware_interface::stoui32(initial_value));
218 catch (
const std::invalid_argument & err)
220 throw std::invalid_argument(
222 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
223 initial_value, handle_name_, data_type_.to_string()));
226 else if (data_type_ == hardware_interface::HandleDataType::INT32)
230 value_ptr_ =
nullptr;
231 value_ = initial_value.empty()
232 ?
static_cast<int32_t
>(std::numeric_limits<int32_t>::max())
233 :
static_cast<int32_t
>(hardware_interface::stoi32(initial_value));
235 catch (
const std::invalid_argument & err)
237 throw std::invalid_argument(
239 FMT_COMPILE(
"Invalid initial value: '{}' parsed for interface: '{}' with type: '{}'"),
240 initial_value, handle_name_, data_type_.to_string()));
245 throw std::runtime_error(
247 FMT_COMPILE(
"Invalid data type: '{}' for interface: {}. Check supported types."),
248 data_type, handle_name_));
254 interface_description.get_prefix_name(), interface_description.get_interface_name(),
255 interface_description.get_data_type_string(),
260 [[deprecated(
"Use InterfaceDescription for initializing the Interface")]]
262 explicit Handle(
const std::string & interface_name)
263 : interface_name_(interface_name), handle_name_(
"/" + interface_name_), value_ptr_(
nullptr)
267 [[deprecated(
"Use InterfaceDescription for initializing the Interface")]]
269 explicit Handle(
const char * interface_name)
270 : interface_name_(interface_name), handle_name_(
"/" + interface_name_), value_ptr_(
nullptr)
285 Handle(
Handle && other)
noexcept { swap(*
this, other); }
296 inline operator bool()
const {
return value_ptr_ !=
nullptr; }
298 const std::string & get_name()
const {
return handle_name_; }
300 const std::string & get_interface_name()
const {
return interface_name_; }
302 const std::string & get_prefix_name()
const {
return prefix_name_; }
314 template <
typename T =
double>
317 std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
318 return get_optional<T>(lock);
331 template <
typename T =
double>
332 [[nodiscard]] std::optional<T>
get_optional(std::shared_lock<std::shared_mutex> & lock)
const
334 if (!lock.owns_lock())
340 if constexpr (std::is_same_v<T, double>)
344 case HandleDataType::DOUBLE:
345 THROW_ON_NULLPTR(value_ptr_);
347 case HandleDataType::BOOL:
354 rclcpp::get_logger(get_name()),
"%s",
357 "Casting bool to double for interface '{}'. Better use get_optional<bool>()."),
362 return static_cast<double>(std::get<bool>(value_));
363 case HandleDataType::FLOAT32:
364 case HandleDataType::UINT8:
365 case HandleDataType::INT8:
366 case HandleDataType::UINT16:
367 case HandleDataType::INT16:
368 case HandleDataType::UINT32:
369 case HandleDataType::INT32:
370 throw std::runtime_error(
373 "Data type: '{}' will not be casted to double for interface: {}. Use "
374 "get_optional<{}>() instead."),
375 data_type_.to_string(), get_name(), data_type_.to_string()));
377 throw std::runtime_error(
379 FMT_COMPILE(
"Data type: '{}' cannot be casted to double for interface: {}"),
380 data_type_.to_string(), get_name()));
385 return std::get<T>(value_);
387 catch (
const std::bad_variant_access & err)
389 throw std::runtime_error(
391 FMT_COMPILE(
"Invalid data type: '{}' access for interface: {} expected: '{}'"),
392 get_type_name<T>(), get_name(), data_type_.to_string()));
410 typename T,
typename = std::enable_if_t<
411 !std::is_same_v<std::decay_t<T>, std::shared_lock<std::shared_mutex>>>>
412 [[nodiscard]]
bool get_value(T & value,
bool wait_for_lock)
const
416 std::shared_lock<std::shared_mutex> lock(handle_mutex_);
421 std::shared_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
437 template <
typename T>
438 [[nodiscard]]
bool set_value(
const T & value,
bool wait_for_lock)
442 std::unique_lock<std::shared_mutex> lock(handle_mutex_);
447 std::unique_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
463 template <
typename T>
466 std::unique_lock<std::shared_mutex> lock(handle_mutex_, std::try_to_lock);
482 template <
typename T>
483 [[nodiscard]]
bool set_value(std::unique_lock<std::shared_mutex> & lock,
const T & value)
485 if (!lock.owns_lock())
491 if constexpr (std::is_same_v<T, double>)
494 THROW_ON_NULLPTR(value_ptr_);
499 if (!std::holds_alternative<T>(value_))
501 throw std::runtime_error(
503 FMT_COMPILE(
"Invalid data type: '{}' access for interface: {} expected: '{}'"),
504 get_type_name<T>(), get_name(), data_type_.to_string()));
512 std::shared_mutex & get_mutex()
const {
return handle_mutex_; }
514 HandleDataType get_data_type()
const {
return data_type_; }
519 bool is_valid()
const
521 return (value_ptr_ !=
nullptr) || !std::holds_alternative<std::monostate>(value_);
534 template <
typename T>
535 [[nodiscard]]
bool get_value(std::shared_lock<std::shared_mutex> & lock, T & value)
const
537 if (!lock.owns_lock())
543 if constexpr (std::is_same_v<T, double>)
547 case HandleDataType::DOUBLE:
548 THROW_ON_NULLPTR(value_ptr_);
551 case HandleDataType::BOOL:
558 rclcpp::get_logger(get_name()),
559 "Casting bool to double for interface: %s. Better use get_optional<bool>().",
563 value =
static_cast<double>(std::get<bool>(value_));
565 case HandleDataType::FLOAT32:
566 case HandleDataType::UINT8:
567 case HandleDataType::INT8:
568 case HandleDataType::UINT16:
569 case HandleDataType::INT16:
570 case HandleDataType::UINT32:
571 case HandleDataType::INT32:
572 throw std::runtime_error(
575 "Data type: '{}' will not be casted to double for interface: {}. Use "
576 "get_optional<{}>() instead."),
577 data_type_.to_string(), get_name(), data_type_.to_string()));
579 throw std::runtime_error(
581 FMT_COMPILE(
"Data type: '{}' cannot be casted to double for interface: {}"),
582 data_type_.to_string(), get_name()));
587 value = std::get<T>(value_);
590 catch (
const std::bad_variant_access & err)
592 throw std::runtime_error(
594 FMT_COMPILE(
"Invalid data type: '{}' access for interface: {} expected: '{}'"),
595 get_type_name<T>(), get_name(), data_type_.to_string()));
600 void copy(
const Handle & other)
noexcept
602 std::scoped_lock lock(other.handle_mutex_, handle_mutex_);
604 interface_name_ = other.interface_name_;
605 handle_name_ = other.handle_name_;
606 value_ = other.value_;
607 data_type_ = other.data_type_;
608 if (std::holds_alternative<std::monostate>(value_))
610 value_ptr_ = other.value_ptr_;
614 value_ptr_ = std::get_if<double>(&value_);
618 void swap(Handle & first, Handle & second)
noexcept
620 std::scoped_lock lock(first.handle_mutex_, second.handle_mutex_);
621 std::swap(first.prefix_name_, second.prefix_name_);
622 std::swap(first.interface_name_, second.interface_name_);
623 std::swap(first.handle_name_, second.handle_name_);
624 std::swap(first.value_, second.value_);
625 std::swap(first.data_type_, second.data_type_);
626 std::swap(first.value_ptr_, second.value_ptr_);
632 std::string interface_name_;
633 std::string handle_name_;
638 double * value_ptr_ =
nullptr;
640 mutable std::shared_mutex handle_mutex_;
646 mutable bool notified_ =
false;