class OroGen::Spec::Port

Generic representation of ports. The actual ports are either instance of InputPort or OutputPort

Attributes

name[R]

The port name

task[R]

The port task

type[R]

The port type. It can be nil for dynamic ports

Public Class Methods

compute_max_marshalling_size(type, max_sizes) click to toggle source

Returns the maximum size of a marshalled sample coming out of this port

If the type on this port contains variable-size containers, this method will return nil unless the 'max_sizes' map specifies their size

# File lib/orogen/spec/port.rb, line 230
def self.compute_max_marshalling_size(type, max_sizes)
    sample = type.new

    path = []
    if initialize_max_size_sample(path, sample, max_sizes)
        sample.to_byte_array(:remove_trailing_skips => false).length
    end
end
initialize_max_size_sample(path, sample, max_sizes) click to toggle source
# File lib/orogen/spec/port.rb, line 169
def self.initialize_max_size_sample(path, sample, max_sizes)
    sample_t = sample.class
    if !(sample_t <= Typelib::Type) || !sample_t.contains?(Typelib::ContainerType)
        return true
    end

    path = path.dup

    if sample.kind_of?(Typelib::ContainerType)
        max_size = max_sizes[path.join(".")]
        if !max_size
            return false
        end

        if path.empty? then path = ["[]"]
        else path[-1] = "#{path[-1]}[]"
        end

        element = sample_t.deference.new
        if !initialize_max_size_sample(path, element, max_sizes)
            return false
        end
        
        Typelib.copy(sample, sample.class.of_size(max_size, element))
        return true

    elsif sample.kind_of?(Typelib::ArrayType)
        if path.empty? then path = ["[]"]
        else path[-1] = "#{path[-1]}[]"
        end
        element = sample_t.deference.new
        if !initialize_max_size_sample(path, element, max_sizes)
            return false
        end

        sample_t.size.times do |i|
            sample[i] = element
        end
        return true

    elsif sample.kind_of?(Typelib::CompoundType)
        path << nil
        sample_t.each_field do |field_name, _|
            field = sample.raw_get_field(field_name)
            path[-1] = field_name
            if !initialize_max_size_sample(path, field, max_sizes)
                return false
            end
        end
        return true
    end

    raise InternalError, "unknown case in initialize_max_size_sample for #{path.join(".")} of type #{sample_t.name}"
end
new(task, name, type, options = Hash.new) click to toggle source
# File lib/orogen/spec/port.rb, line 90
def initialize(task, name, type, options = Hash.new)
    if !name.kind_of?(Regexp)
        name = name.to_s
        if name !~ /^\w+$/
            raise ArgumentError, "port names need to be valid C++ identifiers, i.e. contain only alphanumeric characters and _ (got #{name})"
        end
    elsif !type && !dynamic?
        raise ArgumentError, "only dynamic ports are allowed to have no type"
    end

    if type
        type = task.project.find_interface_type(type)
        OroGen.validate_toplevel_type(type)
        if type.name == "/std/vector<double>"
            Spec.warn "#{type.name} is used as the port type for #{name}, logging it will not be possible"
        end
    end
    @task, @name, @type = task, name, type

    @doc = nil
    @max_sizes = Hash.new
    keep_last_written_value :initial
end
resolve_max_size_path(type, name) click to toggle source
# File lib/orogen/spec/port.rb, line 121
def self.resolve_max_size_path(type, name)
    resolved_type = name.split('.').inject(type) do |resolved_type, element|
        match_deference = element.match(/(\[\])*$/)

        if !match_deference.pre_match.empty?
            resolved_type = resolved_type[match_deference.pre_match]
        end

        (match_deference[0].length / 2).times do
            resolved_type = resolved_type.deference
        end
        resolved_type
    end

    if !(resolved_type <= Typelib::ContainerType)
        raise ArgumentError, "#{name} resolves to the #{resolved_type.name} type in #{type.name}, which is not a variable size container"
    end
    resolved_type
end
validate_max_sizes_spec(resolved_type, values) click to toggle source
# File lib/orogen/spec/port.rb, line 141
def self.validate_max_sizes_spec(resolved_type, values)
    values =
        if values.respond_to?(:to_ary)
            # values is either [spec] or [vector_size, spec]
            # This is used by dsl_attribute implementations of
            # max_sizes

            if values.size == 1
                values[0].to_hash
            elsif values.size == 2
                values[1].to_hash.merge('' => values[0])
            end
        elsif values.respond_to?(:to_hash)
            # Direct call
            values.to_hash
        else
            raise ArgumentError, "expected a one or two element array or a hash, got #{values.inspect}"
        end

    values.each do |name, value|
        if resolved_type
            resolve_max_size_path(resolved_type, name)
        end
        value.to_int
    end
    values
end

Public Instance Methods

dynamic() click to toggle source

Declares that this port can be connected/disconnected while the task context is running. It is the opposite of static.

This is the default

# File lib/orogen/spec/port.rb, line 81
def dynamic; @static = false end
dynamic?() click to toggle source

True if this is a dynamic port model, false otherwise

# File lib/orogen/spec/port.rb, line 88
def dynamic?; false end
each_interface_type() { |type| ... } click to toggle source
# File lib/orogen/spec/port.rb, line 19
def each_interface_type
    return enum_for(__method__) if !block_given?
    yield type
end
max_marshalling_size() click to toggle source

Returns the maximum marshalled size of a sample from this port, as marshalled by typelib

If the type contains variable-size containers, the result is dependent on the values given to max_sizes. If not enough is known, this method will return nil.

# File lib/orogen/spec/port.rb, line 294
def max_marshalling_size
    resolved_type = task.project.intermediate_type_for(type)
    OutputPort.compute_max_marshalling_size(resolved_type, max_sizes)
end
max_sizes('name.to[].field' => value, 'name.other' => value) → self click to toggle source
max_sizes(10, 'name.to[].field' => value, 'name.other' => value) → self
max_sizes → current size specification

Sets the maximum allowed size for the variable-size containers in type. The mapping is given as path.to.field => size, where [] is used to get elements of an array or variable-size container.

If the port type is a container itself, the second form is used, where the first argument is the container size and the rest specifies its element sizes (and must start with [])

For instance, with the types

struct A
{
    std::vector<int> values;
};
struct B
{
    std::vector<A> field;
};

Then sizes on a port of type B would be given with

port.max_sizes('field' => 10, 'field[].values' => 20)

while the sizes on a port of type std::vector<A> would be given with

port.max_sizes(10, '[].values' => 20)

Finally, on a port of type std::vector<std::vector<A>>, one would use

port.max_sizes(10, '[]' => 20, '[][].values' => 30)
# File lib/orogen/spec/port.rb, line 280
dsl_attribute :max_sizes do |*values|
    # Validate that all values are integers and all names map to
    # known types
    resolved_type = task.project.intermediate_type_for(type)
    values = OutputPort.validate_max_sizes_spec(resolved_type, values)
    @max_sizes.merge(values)
end
orocos_type_name() click to toggle source

The port name as it is registered on RTT

# File lib/orogen/spec/port.rb, line 15
def orocos_type_name
    type.name
end
pretty_print(pp) click to toggle source
# File lib/orogen/spec/port.rb, line 83
def pretty_print(pp)
    pp.text "[#{self.kind_of?(InputPort) ? "in" : "out"}]#{name}:#{type_name}"
end
static() click to toggle source

Declares that this port can be connected/disconnected only when the task context is in a non-running state.

The default is that the port is dynamic, i.e. can be connected/disconnected regardless of the task context's state.

See also dynamic

# File lib/orogen/spec/port.rb, line 75
def static; @static = true end
static?() click to toggle source

True if the task context supports only static connections on this port, and false otherwise

See static for more details.

# File lib/orogen/spec/port.rb, line 66
def static?; !!@static end
to_h() click to toggle source

Converts this model into a representation that can be fed to e.g. a JSON dump, that is a hash with pure ruby key / values.

The generated hash has the following keys:

name: the name
type: the type (as marshalled with Typelib::Type#to_h)
direction: either the string 'input' or 'output'
doc: the documentation string

@return [Hash]

# File lib/orogen/spec/port.rb, line 35
def to_h
    Hash[
        direction: (if kind_of?(OutputPort) then 'output' else 'input' end),
        name: name,
        type: type.to_h,
        doc: (doc || "")
    ]
end
type_name() click to toggle source

The port type name

# File lib/orogen/spec/port.rb, line 13
def type_name; type.name end