556 lines
16 KiB
C++
556 lines
16 KiB
C++
/*
|
|
* (c) Copyright, Real-Time Innovations, 2017.
|
|
* All rights reserved.
|
|
*
|
|
* No duplications, whole or partial, manual or electronic, may be made
|
|
* without express written permission. Any such copies, or
|
|
* revisions thereof, must display this notice unaltered.
|
|
* This code contains trade secrets of Real-Time Innovations, Inc.
|
|
*/
|
|
|
|
#ifndef RTI_ROUTING_PROCESSOR_ROUTE_HPP_
|
|
#define RTI_ROUTING_PROCESSOR_ROUTE_HPP_
|
|
|
|
#include <dds/core/Value.hpp>
|
|
#include <dds/core/SafeEnumeration.hpp>
|
|
#include <rti/core/NativeValueType.hpp>
|
|
|
|
#include "routingservice/routingservice_processor.h"
|
|
#include "routingservice/routingservice_processor_impl.h"
|
|
|
|
#include <dds/core/xtypes/DynamicData.hpp>
|
|
#include <dds/sub/SampleInfo.hpp>
|
|
#include <rti/routing/adapter/AdapterPlugin.hpp>
|
|
#include <rti/routing/processor/Input.hpp>
|
|
#include <rti/routing/processor/Output.hpp>
|
|
#include <rti/routing/processor/LoanedSamples.hpp>
|
|
#include <rti/routing/processor/PortIterator.hpp>
|
|
|
|
namespace rti { namespace routing { namespace processor {
|
|
|
|
namespace detail {
|
|
|
|
class ProcessorForwarder;
|
|
|
|
}
|
|
|
|
class Route;
|
|
|
|
template <typename PORT> struct port_list;
|
|
|
|
template <> struct port_list<Input>
|
|
{
|
|
static std::vector<Input>& get(Route& route);
|
|
};
|
|
|
|
template <> struct port_list<Output>
|
|
{
|
|
static std::vector<Output>& get(Route& route);
|
|
};
|
|
|
|
/** @ingroup RTI_RoutingServiceProcessorModule
|
|
*
|
|
* @class rti::routing::processor::Route
|
|
*
|
|
* @brief Representation of the Route object that owns a Processor.
|
|
*
|
|
* This class provides an interface to access the capabilities of a Route, such
|
|
* as retrieving any of its inputs and outputs. Usage of this class
|
|
* is restricted within the Processor context where the object is passed.
|
|
*
|
|
* An example of how to use this object is shown below. This example illustrates
|
|
* a simple use case of reading from all inputs and writing to all outputs,
|
|
* assuming that the sample data and info have the same representation and
|
|
* type.
|
|
*
|
|
* \code{.c++}
|
|
* using dds::core::xtypes::DynamicData;
|
|
* using dds::sub::SampleInfo;
|
|
* using namespace rti::routing::processor;
|
|
*
|
|
* ...
|
|
*
|
|
* for (auto input : route.inputs<DynamicData>()) {
|
|
* LoanedSamples<DynamicData> samples = input->read();
|
|
*
|
|
* for (auto output : route.outputs<DynamicData>()) {
|
|
* for(auto sample = samples) {
|
|
* output.write(sample.data(), sample.info());
|
|
* }
|
|
* }
|
|
* }
|
|
* \endcode
|
|
*/
|
|
class Route {
|
|
|
|
public:
|
|
|
|
template <typename DataRep, typename InfoRep = dds::sub::SampleInfo>
|
|
struct Inputs {
|
|
typedef PortIterator<Input, DataRep, InfoRep> iterator;
|
|
|
|
Inputs(RTI_RoutingServiceRoute *native_route)
|
|
: native_route_(native_route)
|
|
{
|
|
}
|
|
|
|
iterator begin()
|
|
{
|
|
return iterator(native_route_);
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
return iterator();
|
|
}
|
|
|
|
private:
|
|
RTI_RoutingServiceRoute *native_route_;
|
|
};
|
|
|
|
template <typename DataRep, typename InfoRep = dds::sub::SampleInfo>
|
|
struct Outputs {
|
|
typedef PortIterator<Output, DataRep, InfoRep> iterator;
|
|
|
|
Outputs(RTI_RoutingServiceRoute *native_route)
|
|
: native_route_(native_route)
|
|
{
|
|
}
|
|
|
|
iterator begin()
|
|
{
|
|
return iterator(native_route_);
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
return iterator();
|
|
}
|
|
|
|
private:
|
|
RTI_RoutingServiceRoute *native_route_;
|
|
};
|
|
|
|
|
|
/**
|
|
* @brief Returns the total number of inputs in this Route.
|
|
*
|
|
*/
|
|
int32_t input_count() const
|
|
{
|
|
return RTI_RoutingServiceRoute_get_input_count(native_route_);
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the total number of outputs in this Route.
|
|
*
|
|
*/
|
|
int32_t output_count() const
|
|
{
|
|
return RTI_RoutingServiceRoute_get_output_count(native_route_);
|
|
}
|
|
|
|
/**
|
|
*@brief Checks whether the Input at the specified index is enabled
|
|
*
|
|
*/
|
|
bool input_enabled(int32_t index) const
|
|
{
|
|
return RTI_RoutingServiceRoute_is_input_enabled(native_route_, index)
|
|
? true
|
|
: false;
|
|
}
|
|
|
|
/**
|
|
*@brief Checks whether the Input at the specified index is enabled
|
|
*
|
|
*/
|
|
bool output_enabled(int32_t index) const
|
|
{
|
|
return RTI_RoutingServiceRoute_is_output_enabled(native_route_, index)
|
|
? true
|
|
: false;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the Input object at the specified index.
|
|
*
|
|
* Input indexes are assigned in increasing creation order, starting at 0.
|
|
* The creation order is the same order than the inputs are defined within
|
|
* the Route configuration.
|
|
*
|
|
* The returned object can be used to construct the appropriate TypedInput,
|
|
* which can be used for reading data.
|
|
*
|
|
* @param[in] index
|
|
* The index of the Input to be retrieved.
|
|
*
|
|
* @return The Input at the specified index.
|
|
*
|
|
* @see TypedInput
|
|
*
|
|
*/
|
|
Input& input(int32_t index)
|
|
{
|
|
return *(get_input_at_index(index));
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the Input object with the specified name or throws an
|
|
* exception if the input with the given name is not found or if it is
|
|
* found but is not enabled.
|
|
*
|
|
* \b NOTE: The condition that the input must be enabled will be removed
|
|
* in a future version. This is being tracked with issue ID ROUTING-1131.
|
|
*
|
|
* @param[in] name The input configuration name
|
|
*
|
|
* @see TypedInput::name
|
|
* @throw std::logic_error
|
|
*/
|
|
Input& input(const std::string& name)
|
|
{
|
|
return *(lookup_input(name));
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the TypedInput object at the specified index.
|
|
*
|
|
* The returned object is typed so it can read samples whose type is
|
|
* \p DataRep for data, and \p InfoRep for info. These types must
|
|
* match the expected type representations of the underlying
|
|
* rti::routing::adapter::StreamReader.
|
|
*
|
|
* Typically, these template arguments are typed
|
|
* dds::core::xtypes::DynamicData and dds::sub::SampleInfo, respectively.
|
|
*
|
|
* @warning This operation performs no type integrity check. It is
|
|
* responsibility of the caller to ensure the provided template
|
|
* arguments match with the expected types of the input. Otherwise
|
|
* behavior accessing the input is undefined.
|
|
*
|
|
* @return The TypedInput object at the specified index.
|
|
*
|
|
* @see input(int32_t)
|
|
* @see TypedInput
|
|
*/
|
|
template <typename DataRep, typename InfoRep>
|
|
TypedInput<DataRep, InfoRep> input(int32_t index)
|
|
{
|
|
return &input(index);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>input<DataRep, InfoRep>(int32_t)</tt> with
|
|
* InfoRep = dds::sub::SampleInfo.
|
|
*
|
|
*/
|
|
template <typename DataRep>
|
|
TypedInput<DataRep> input(int32_t index)
|
|
{
|
|
return input<DataRep, dds::sub::SampleInfo>(index);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>input<DataRep, InfoRep>(int32_t)</tt> but using
|
|
* the configuration name of the input.
|
|
*
|
|
*/
|
|
template <typename DataRep, typename InfoRep>
|
|
TypedInput<DataRep, InfoRep> input(const std::string& name)
|
|
{
|
|
return &input(name);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>input<DataRep, InfoRep>(std::string&)</tt> with
|
|
* InfoRep = dds::sub::SampleInfo.
|
|
*/
|
|
template <typename DataRep>
|
|
TypedInput<DataRep> input(const std::string& name)
|
|
{
|
|
return input<DataRep, dds::sub::SampleInfo>(name);
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the Output object at the specified index.
|
|
*
|
|
* Output indexes are assigned in increasing creation order, starting at 0.
|
|
* The creation order is the same order than the outputs are defined within
|
|
* the Route configuration.
|
|
*
|
|
* The returned object can be used to construct the appropriate TypedOutput,
|
|
* which can be used for writing data.
|
|
*
|
|
* @param[in] index
|
|
* The index of the Output to be retrieved.
|
|
*
|
|
* @return The Output at the specified index.
|
|
*
|
|
* @see TypedOutput
|
|
*
|
|
*/
|
|
Output& output(int32_t index)
|
|
{
|
|
return *(get_output_at_index(index));
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the Output object with the specified name or throws an
|
|
* exception if the output with the given name is not found or if it is
|
|
* found but is not enabled.
|
|
*
|
|
* \b NOTE: The condition that the input must be enabled will be removed
|
|
* in a future version. This is being tracked with issue ID ROUTING-1131.
|
|
*
|
|
* @param[in] name The output configuration name
|
|
*
|
|
* @see TypedOutput::name
|
|
* @throw std::logic_error
|
|
*/
|
|
Output& output(const std::string& name)
|
|
{
|
|
return *(lookup_output(name));
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the TypedOutput object at the specified index.
|
|
*
|
|
* The returned object is typed so it can write samples whose type is
|
|
* \p DataRep for data, and \p InfoRep for info. These types must
|
|
* match the expected type representations of the underlying
|
|
* rti::routing::adapter::StreamWriter.
|
|
*
|
|
* Typically, these template arguments are typed
|
|
* dds::core::xtypes::DynamicData and dds::sub::SampleInfo, respectively.
|
|
*
|
|
* @warning This operation performs no type integrity check. It is
|
|
* responsibility of the caller to ensure the provided template
|
|
* arguments match with the expected types of the output. Otherwise
|
|
* behavior accessing the output is undefined.
|
|
*
|
|
* @return The TypedOutput object at the specified index.
|
|
*
|
|
* @see input(int32_t)
|
|
*/
|
|
template <typename DataRep, typename InfoRep>
|
|
TypedOutput<DataRep, InfoRep> output(int32_t index)
|
|
{
|
|
return &output(index);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>output<DataRep, InfoRep>(int32_t)</tt> with
|
|
* InfoRep = dds::sub::SampleInfo.
|
|
*
|
|
*/
|
|
template <typename DataRep>
|
|
TypedOutput<DataRep> output(int32_t index)
|
|
{
|
|
return output<DataRep, dds::sub::SampleInfo>(index);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>output<DataRep, InfoRep>(int32_t)</tt> but using
|
|
* the configuration name of the output.
|
|
*
|
|
*/
|
|
template <typename DataRep, typename InfoRep>
|
|
TypedOutput<DataRep, InfoRep> output(const std::string& name)
|
|
{
|
|
return &output(name);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>output<DataRep, InfoRep>(std::string&)</tt> with
|
|
* InfoRep = dds::sub::SampleInfo.
|
|
*/
|
|
template <typename DataRep>
|
|
TypedOutput<DataRep> output(const std::string& name)
|
|
{
|
|
return output<DataRep, dds::sub::SampleInfo>(name);
|
|
}
|
|
|
|
/**
|
|
* @brief Returns an accessor for the contained inputs.
|
|
*
|
|
* The returned object that allows iterating over the
|
|
* contained inputs, treating them as <tt>TypedInput<DataRep, InfoRep></tt>.
|
|
*
|
|
* @see <tt>Inputs<DataRep, InfoRep></tt>
|
|
* @see <tt>TypedInput<DataRep, InfoRep> input(int32_t index)</tt>
|
|
*/
|
|
template <typename DataRep, typename InfoRep>
|
|
Inputs<DataRep, InfoRep> inputs()
|
|
{
|
|
return Inputs<DataRep, InfoRep>(native_route_);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>Inputs<DataRep, InfoRep> inputs()</tt> with
|
|
* InfoRep = dds::sub::SampleInfo.
|
|
*/
|
|
template <typename DataRep>
|
|
Inputs<DataRep> inputs()
|
|
{
|
|
return inputs<DataRep, dds::sub::SampleInfo>();
|
|
}
|
|
|
|
/**
|
|
* @brief Returns an accessor for the contained outputs.
|
|
*
|
|
* The returned object that allows iterating over the
|
|
* contained outputs, treating them as <tt>TypedOutput<DataRep, InfoRep></tt>.
|
|
*
|
|
* @see <tt>Outputs<DataRep, InfoRep></tt>
|
|
* @see <tt>TypedOutput<DataRep, InfoRep> input(int32_t index)</tt>
|
|
*/
|
|
template <typename DataRep, typename InfoRep>
|
|
Outputs<DataRep, InfoRep> outputs()
|
|
{
|
|
return Outputs<DataRep, InfoRep>(native_route_);
|
|
}
|
|
|
|
/**
|
|
* @brief Same as <tt>Inputs<DataRep, InfoRep> outputs()</tt> with
|
|
* InfoRep = dds::sub::SampleInfo.
|
|
*/
|
|
template <typename DataRep>
|
|
Outputs<DataRep> outputs()
|
|
{
|
|
return outputs<DataRep, dds::sub::SampleInfo>();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Changes the event period of this Route.
|
|
*
|
|
* This operation can be called many times within the same periodic event,
|
|
* in which only the last call will have effect.
|
|
*
|
|
* The operation will enable the periodic event in this route if this
|
|
* operation is called for the first time in a route with no period set
|
|
* in the configuration.
|
|
*
|
|
* @param[in] period New session period
|
|
*/
|
|
void period(const dds::core::Duration& period)
|
|
{
|
|
struct DDS_Duration_t native_period = DDS_DURATION_ZERO;
|
|
rti::core::native_conversions::to_native(native_period, period);
|
|
RTI_RoutingServiceRoute_set_period(
|
|
native_route_,
|
|
&native_period);
|
|
}
|
|
|
|
dds::core::Duration period() const
|
|
{
|
|
struct DDS_Duration_t native_period = DDS_DURATION_ZERO;
|
|
RTI_RoutingServiceRoute_get_period(
|
|
native_route_,
|
|
&native_period);
|
|
|
|
return rti::core::native_conversions::from_native(native_period);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Returns the fully qualified of this Route, derived from the configuration.
|
|
*
|
|
*/
|
|
const std::string& full_name() const
|
|
{
|
|
return full_name_;
|
|
}
|
|
|
|
|
|
private:
|
|
friend class detail::ProcessorForwarder;
|
|
friend class Output;
|
|
friend struct port_list<Input>;
|
|
friend struct port_list<Output>;
|
|
|
|
typedef std::vector<Input>::iterator private_input_it;
|
|
typedef std::vector<Output>::iterator private_output_it;
|
|
|
|
Route& operator= (const Route& other);
|
|
|
|
Route(RTI_RoutingServiceRoute *native_route,
|
|
RTI_RoutingServiceEnvironment *native_env)
|
|
: native_route_(native_route),
|
|
native_env_(native_env)
|
|
{
|
|
const char *native_full_name =
|
|
RTI_RoutingServiceRoute_get_full_name(native_route);
|
|
if (native_full_name == nullptr) {
|
|
throw dds::core::InvalidArgumentError(
|
|
"Native Route has invalid full name");
|
|
}
|
|
full_name_ = native_full_name;
|
|
}
|
|
|
|
Input* get_input_at_index(int32_t index)
|
|
{
|
|
RTI_RoutingServiceInput *native_input =
|
|
RTI_RoutingServiceRoute_get_input_at(native_route_, index);
|
|
if (native_input == NULL) {
|
|
throw dds::core::InvalidArgumentError(
|
|
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
|
|
}
|
|
|
|
return static_cast<Input*>(RTI_RoutingServiceInput_get_user_data(native_input));
|
|
}
|
|
|
|
Output* get_output_at_index(int32_t index)
|
|
{
|
|
RTI_RoutingServiceOutput *native_output =
|
|
RTI_RoutingServiceRoute_get_output_at(native_route_, index);
|
|
if (native_output == NULL) {
|
|
throw dds::core::InvalidArgumentError(
|
|
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
|
|
}
|
|
|
|
return static_cast<Output*>(RTI_RoutingServiceOutput_get_user_data(native_output));
|
|
}
|
|
|
|
|
|
Input* lookup_input(const std::string& name)
|
|
{
|
|
RTI_RoutingServiceInput *native_input =
|
|
RTI_RoutingServiceRoute_lookup_input_by_name(
|
|
native_route_,
|
|
name.c_str());
|
|
if (native_input == NULL) {
|
|
throw dds::core::InvalidArgumentError(
|
|
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
|
|
}
|
|
return static_cast<Input*>(RTI_RoutingServiceInput_get_user_data(native_input));
|
|
|
|
}
|
|
|
|
Output* lookup_output(const std::string& name)
|
|
{
|
|
RTI_RoutingServiceOutput *native_output =
|
|
RTI_RoutingServiceRoute_lookup_output_by_name(
|
|
native_route_,
|
|
name.c_str());
|
|
if (native_output == NULL) {
|
|
throw dds::core::InvalidArgumentError(
|
|
RTI_RoutingServiceEnvironment_get_error_message(native_env_));
|
|
}
|
|
return static_cast<Output*>(RTI_RoutingServiceOutput_get_user_data(native_output));
|
|
|
|
}
|
|
|
|
private:
|
|
RTI_RoutingServiceRoute *native_route_;
|
|
RTI_RoutingServiceEnvironment *native_env_;
|
|
std::string full_name_;
|
|
|
|
};
|
|
|
|
|
|
} } }
|
|
|
|
#endif // RTI_ROUTING_PROCESSOR_ROUTE_HPP_
|