Skip to content
Snippets Groups Projects
event.hh 3.9 KiB
Newer Older
Joseph Mirabel's avatar
Joseph Mirabel committed
// Copyright (c) 2018, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)

#ifndef __SOT_EVENT_H__
Guilhem Saurel's avatar
Guilhem Saurel committed
#define __SOT_EVENT_H__
Joseph Mirabel's avatar
Joseph Mirabel committed

#include <dynamic-graph/command-bind.h>
#include <dynamic-graph/command-getter.h>
Joseph Mirabel's avatar
Joseph Mirabel committed
#include <dynamic-graph/command-setter.h>
Guilhem Saurel's avatar
Guilhem Saurel committed
#include <dynamic-graph/entity.h>
#include <dynamic-graph/pool.h>
#include <dynamic-graph/signal-ptr.h>
#include <dynamic-graph/signal-time-dependent.h>
#include <dynamic-graph/signal.h>
Joseph Mirabel's avatar
Joseph Mirabel committed

#include <sot/core/config.hh>

namespace dynamicgraph {
Guilhem Saurel's avatar
Guilhem Saurel committed
namespace sot {
/// Event
///
/// This entity detects changes in value of an input boolean signal
///
/// Input signal is
///   - condition (boolean),
/// Output signal is
///   - check
/// output value is true if value of input signal changes with respect to the
/// evaluation.
///
/// Method addSignal stores signals that are recomputed each time the output
/// signal is recomputed and the value is true. One typical use case of this
/// feature consists in plugging the output signal to a ROS topic using
/// dynamicgraph::RosPublish entity (see dynamic_graph_bridge) and to call
/// addSignal with the trigger signal of the RosPublish entity as the input.
/// Thus each time the output signal changes value, the new value is published
/// to the ROS topic.
///
/// If command setOnlyUp is called with true as input, signals are recomputed
/// only if the output value switches from false to true.

Guilhem Saurel's avatar
Guilhem Saurel committed
class SOT_CORE_DLLAPI Event : public dynamicgraph::Entity {
  DYNAMIC_GRAPH_ENTITY_DECL();

  Event(const std::string &name)
Guilhem Saurel's avatar
Guilhem Saurel committed
      : Entity(name),
        checkSOUT("Event(" + name + ")::output(bool)::check"),
Guilhem Saurel's avatar
Guilhem Saurel committed
        conditionSIN(NULL, "Event(" + name + ")::input(bool)::condition"),
Guilhem Saurel's avatar
Guilhem Saurel committed
        lastVal_(2),  // lastVal_ should be different true and false.
        timeSinceUp_(0),
        repeatAfterNIterations_(0) {
Guilhem Saurel's avatar
Guilhem Saurel committed
    checkSOUT.setFunction(boost::bind(&Event::check, this, _1, _2));
    signalRegistration(conditionSIN);
    signalRegistration(checkSOUT);

    using command::makeCommandVoid1;
Guilhem Saurel's avatar
Guilhem Saurel committed
    std::string docstring =
        "\n"
        "    Add a signal\n";
Guilhem Saurel's avatar
Guilhem Saurel committed
    addCommand("addSignal",
               makeCommandVoid1(*this, &Event::addSignal, docstring));

Guilhem Saurel's avatar
Guilhem Saurel committed
    docstring =
        "\n"
        "    Get list of signals\n";
Guilhem Saurel's avatar
Guilhem Saurel committed
    addCommand("list", new command::Getter<Event, std::string>(
                           *this, &Event::getSignalsByName, docstring));

    docstring =
Guilhem Saurel's avatar
Guilhem Saurel committed
        "\n"
        "    Repease event if input signal remains True for a while\n"
        "      Input: number of iterations before repeating output\n."
        "        0 for no repetition";
    addCommand("repeat", new command::Setter<Event, int>(*this, &Event::repeat,
                                                         docstring));
Guilhem Saurel's avatar
Guilhem Saurel committed
  }

  ~Event() {}

  /// Header documentation of the python class
  virtual std::string getDocString() const {
    return "Send an event when the input changes\n\n"
           "  The signal triggered is called whenever the condition is "
           "satisfied.\n";
  }

  void addSignal(const std::string &signal) {
    std::istringstream iss(signal);
    triggers.push_back(&PoolStorage::getInstance()->getSignal(iss));
  }

  // Returns the Python string representation of the list of signal names.
  std::string getSignalsByName() const {
    std::ostringstream oss;
    oss << "(";
    for (Triggers_t::const_iterator _sig = triggers.begin();
         _sig != triggers.end(); ++_sig)
      oss << '\'' << (*_sig)->getName() << "\', ";
    oss << ")";
    return oss.str();
  }

Guilhem Saurel's avatar
Guilhem Saurel committed
  void repeat(const int &nbIterations) {
Guilhem Saurel's avatar
Guilhem Saurel committed

 private:
Guilhem Saurel's avatar
Guilhem Saurel committed
  typedef SignalBase<int> *Trigger_t;
  typedef std::vector<Trigger_t> Triggers_t;

  bool &check(bool &ret, const int &time);

  Signal<bool, int> checkSOUT;

  Triggers_t triggers;
  SignalPtr<bool, int> conditionSIN;

  bool lastVal_;
  int timeSinceUp_, repeatAfterNIterations_;
Guilhem Saurel's avatar
Guilhem Saurel committed
};
Guilhem Saurel's avatar
Guilhem Saurel committed
}  // namespace sot
}  // namespace dynamicgraph
#endif  // __SOT_EVENT_H__