Program Listing for File subscriber.hpp

Return to documentation for file (include/message_filters/subscriber.hpp)

// Copyright 2009, Willow Garage, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the Willow Garage nor the names of its
//      contributors may be used to endorse or promote products derived from
//      this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MESSAGE_FILTERS__SUBSCRIBER_HPP_
#define MESSAGE_FILTERS__SUBSCRIBER_HPP_

#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>

#include <rclcpp/rclcpp.hpp>

#include "message_filters/connection.hpp"
#include "message_filters/simple_filter.hpp"

namespace message_filters
{

template<class NodeType = rclcpp::Node>
class SubscriberBase
{
public:
  typedef std::shared_ptr<NodeType> NodePtr;

  virtual ~SubscriberBase() = default;
  virtual void subscribe(
    NodePtr node, const std::string & topic,
    const rclcpp::QoS & qos) = 0;

  virtual void subscribe(
    NodeType * node, const std::string & topic,
    const rclcpp::QoS & qos) = 0;

  virtual void subscribe(
    NodePtr node,
    const std::string & topic,
    const rclcpp::QoS & qos,
    rclcpp::SubscriptionOptions options)
  {
    this->subscribe(node.get(), topic, qos, options);
  }

  virtual void subscribe(
    NodeType * node,
    const std::string & topic,
    const rclcpp::QoS & qos,
    rclcpp::SubscriptionOptions options) = 0;

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  virtual void subscribe(
    NodePtr node, const std::string & topic,
    const rmw_qos_profile_t qos = rmw_qos_profile_default) = 0;

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  virtual void subscribe(
    NodeType * node, const std::string & topic,
    const rmw_qos_profile_t qos = rmw_qos_profile_default) = 0;

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  virtual void subscribe(
    NodePtr node,
    const std::string & topic,
    const rmw_qos_profile_t qos,
    rclcpp::SubscriptionOptions options)
  {
    this->subscribe(
      node.get(), topic, rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos)), options);
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  virtual void subscribe(
    NodeType * node,
    const std::string & topic,
    const rmw_qos_profile_t qos,
    rclcpp::SubscriptionOptions options) = 0;

  virtual void subscribe() = 0;
  virtual void unsubscribe() = 0;
};
template<typename T>
using SubscriberBasePtr = std::shared_ptr<SubscriberBase<T>>;

template<typename M, bool is_adapter = rclcpp::is_type_adapter<M>::value>
struct message_type;

template<typename M>
struct message_type<M, true>
{
  using type = typename M::custom_type;
};

template<typename M>
struct message_type<M, false>
{
  using type = M;
};

template<typename M>
using message_type_t = typename message_type<M>::type;

template<class M, class NodeType = rclcpp::Node>
class Subscriber
  : public SubscriberBase<NodeType>,
  public SimpleFilter<message_type_t<M>>
{
public:
  typedef std::shared_ptr<NodeType> NodePtr;
  typedef message_type_t<M> MessageType;
  typedef MessageEvent<MessageType const> EventType;
  Subscriber(
    NodePtr node, const std::string & topic,
    const rclcpp::QoS & qos)
  {
    subscribe(node, topic, qos);
  }

  Subscriber(
    NodeType * node, const std::string & topic,
    const rclcpp::QoS & qos)
  {
    subscribe(node, topic, qos);
  }

  Subscriber(
    NodePtr node,
    const std::string & topic,
    const rclcpp::QoS & qos,
    rclcpp::SubscriptionOptions options)
  {
    subscribe(node.get(), topic, qos, options);
  }

  Subscriber(
    NodeType * node,
    const std::string & topic,
    const rclcpp::QoS & qos,
    rclcpp::SubscriptionOptions options)
  {
    subscribe(node, topic, qos, options);
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  Subscriber(
    NodePtr node, const std::string & topic,
    const rmw_qos_profile_t qos = rmw_qos_profile_default)
  {
    subscribe(node, topic, rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos)));
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  Subscriber(
    NodeType * node, const std::string & topic,
    const rmw_qos_profile_t qos = rmw_qos_profile_default)
  {
    subscribe(node, topic, qos);
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  Subscriber(
    NodePtr node,
    const std::string & topic,
    const rmw_qos_profile_t qos,
    rclcpp::SubscriptionOptions options)
  {
    subscribe(node.get(), topic, qos, options);
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  Subscriber(
    NodeType * node,
    const std::string & topic,
    const rmw_qos_profile_t qos,
    rclcpp::SubscriptionOptions options)
  {
    subscribe(node, topic, qos, options);
  }

  Subscriber() = default;

  ~Subscriber()
  {
    unsubscribe();
  }

  void subscribe(
    NodePtr node, const std::string & topic,
    const rclcpp::QoS & qos) override
  {
    subscribe(node.get(), topic, qos, rclcpp::SubscriptionOptions());
  }

  void subscribe(
    NodeType * node, const std::string & topic,
    const rclcpp::QoS & qos) override
  {
    subscribe(node, topic, qos, rclcpp::SubscriptionOptions());
  }

  void subscribe(
    NodePtr node,
    const std::string & topic,
    const rclcpp::QoS & qos,
    rclcpp::SubscriptionOptions options) override
  {
    subscribe(node.get(), topic, qos, options);
    node_raw_ = nullptr;
    node_shared_ = node;
  }

  void subscribe(
    NodeType * node,
    const std::string & topic,
    const rclcpp::QoS & qos,
    rclcpp::SubscriptionOptions options) override
  {
    unsubscribe();

    if (!topic.empty()) {
      topic_ = topic;
      qos_ = qos;
      options_ = options;
      sub_ = node->template create_subscription<M>(
        topic, qos,
        [this](const std::shared_ptr<MessageType const> msg) {
          this->cb(EventType(msg));
        }, options);

      node_raw_ = node;
    }
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  void subscribe(
    NodePtr node, const std::string & topic,
    const rmw_qos_profile_t qos = rmw_qos_profile_default) override
  {
    subscribe(
      node.get(), topic, rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos)),
      rclcpp::SubscriptionOptions());
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  void subscribe(
    NodeType * node, const std::string & topic,
    const rmw_qos_profile_t qos = rmw_qos_profile_default) override
  {
    subscribe(
      node, topic, rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos)),
      rclcpp::SubscriptionOptions());
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  void subscribe(
    NodePtr node,
    const std::string & topic,
    const rmw_qos_profile_t qos,
    rclcpp::SubscriptionOptions options) override
  {
    subscribe(node.get(), topic, rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos)), options);
    node_raw_ = nullptr;
    node_shared_ = node;
  }

  [[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
  void subscribe(
    NodeType * node,
    const std::string & topic,
    const rmw_qos_profile_t qos,
    rclcpp::SubscriptionOptions options) override
  {
    unsubscribe();

    if (!topic.empty()) {
      topic_ = topic;
      rclcpp::QoS rclcpp_qos(rclcpp::QoSInitialization::from_rmw(qos));
      qos_ = rclcpp_qos;
      options_ = options;
      sub_ = node->template create_subscription<M>(
        topic, rclcpp_qos,
        [this](const std::shared_ptr<MessageType const> msg) {
          this->cb(EventType(msg));
        }, options);

      node_raw_ = node;
    }
  }

  void subscribe() override
  {
    if (!topic_.empty()) {
      if (node_raw_ != nullptr) {
        subscribe(node_raw_, topic_, qos_, options_);
      } else if (node_shared_ != nullptr) {
        subscribe(node_shared_, topic_, qos_, options_);
      }
    }
  }

  void unsubscribe() override
  {
    sub_.reset();
  }

  std::string getTopic() const
  {
    return this->topic_;
  }

  const typename rclcpp::Subscription<M>::SharedPtr getSubscriber() const {return sub_;}

  template<typename F>
  void connectInput(F & f)
  {
    (void)f;
  }

  void add(const EventType & e)
  {
    (void)e;
  }

private:
  void cb(const EventType & e)
  {
    this->signalMessage(e);
  }

  typename rclcpp::Subscription<M>::SharedPtr sub_;

  NodePtr node_shared_;
  NodeType * node_raw_ {nullptr};

  std::string topic_;
  rclcpp::QoS qos_ = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default));
  rclcpp::SubscriptionOptions options_;
};

}  // namespace message_filters

#endif  // MESSAGE_FILTERS__SUBSCRIBER_HPP_