Class: OroGen::Spec::Port

Inherits:
Object
  • Object
show all
Defined in:
lib/orogen/spec/port.rb

Overview

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

Direct Known Subclasses

InputPort, OutputPort

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(task, name, type, options = Hash.new) ⇒ Port


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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

Instance Attribute Details

#nameObject (readonly)

The port name


9
10
11
# File 'lib/orogen/spec/port.rb', line 9

def name
  @name
end

#taskObject (readonly)

The port task


7
8
9
# File 'lib/orogen/spec/port.rb', line 7

def task
  @task
end

#typeObject (readonly)

The port type. It can be nil for dynamic ports


11
12
13
# File 'lib/orogen/spec/port.rb', line 11

def type
  @type
end

Class Method Details

.compute_max_marshalling_size(type, max_sizes) ⇒ Object

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


230
231
232
233
234
235
236
237
# 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) ⇒ Object

Raises:


169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# 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

.resolve_max_size_path(type, name) ⇒ Object


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# 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) ⇒ Object


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# 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

Instance Method Details

#dynamicObject

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

This is the default


81
# File 'lib/orogen/spec/port.rb', line 81

def dynamic; @static = false end

#dynamic?Boolean

True if this is a dynamic port model, false otherwise


88
# File 'lib/orogen/spec/port.rb', line 88

def dynamic?; false end

#each_interface_type {|type| ... } ⇒ Object

Yields:


19
20
21
22
# File 'lib/orogen/spec/port.rb', line 19

def each_interface_type
    return enum_for(__method__) if !block_given?
    yield type
end

#max_marshalling_sizeObject

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.


294
295
296
297
# 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_sizesObject

:method: max_sizes

:call-seq:

max_sizes('name.to[].field' => value, 'name.other' => value) => self
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)

280
281
282
283
284
285
286
# 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_nameObject

The port name as it is registered on RTT


15
16
17
# File 'lib/orogen/spec/port.rb', line 15

def orocos_type_name
    type.name
end

#pretty_print(pp) ⇒ Object


83
84
85
# File 'lib/orogen/spec/port.rb', line 83

def pretty_print(pp)
    pp.text "[#{self.kind_of?(InputPort) ? "in" : "out"}]#{name}:#{type_name}"
end

#staticObject

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


75
# File 'lib/orogen/spec/port.rb', line 75

def static; @static = true end

#static?Boolean

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

See #static for more details.


66
# File 'lib/orogen/spec/port.rb', line 66

def static?; !!@static end

#to_hHash

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

35
36
37
38
39
40
41
42
# 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_nameObject

The port type name


13
# File 'lib/orogen/spec/port.rb', line 13

def type_name; type.name end