class Syskit::Models::DataServiceModel

Base type for data service models (DataService, Devices, ComBus). Methods defined in this class are available on said models (for instance Device.new_submodel)

Attributes

base_module[RW]

Each subclass of DataServiceModel maps to a “base” module that all instances of DataServiceModel include.

For instance, for DataServiceModel itself, it is DataService

This attribute is the base module for this class of DataServiceModel

orogen_model[R]
Orocos::Spec::TaskContext

the object describing the data

service's interface

Public Class Methods

new(project: Roby.app.default_orogen_project) click to toggle source
Calls superclass method
# File lib/syskit/models/data_service.rb, line 22
def initialize(project: Roby.app.default_orogen_project)
    @orogen_model = OroGen::Spec::TaskContext.new(project)
    super()
end

Public Instance Methods

apply_block(name = nil, &block) click to toggle source

Applies a setup block on a service model

If name is given, that string will be reported as the service name in the block, instead of the actual service name

# File lib/syskit/models/data_service.rb, line 121
def apply_block(name = nil, &block)
    BlockInstanciator.new(self, name).instance_eval(&block)

    # Now initialize the port_mappings hash. We register our own
    # ports as identity (from => from)
    self_mappings = (port_mappings[self] ||= Hash.new)
    each_input_port  { |port| self_mappings[port.name] = port.name }
    each_output_port { |port| self_mappings[port.name] = port.name }
end
as_plan() click to toggle source
# File lib/syskit/models/data_service.rb, line 313
def as_plan
    to_instance_requirements.as_plan
end
clear_model() click to toggle source
Calls superclass method
# File lib/syskit/models/data_service.rb, line 27
def clear_model
    super()
    @orogen_model = OroGen::Spec::TaskContext.new(@orogen_model.project)
    port_mappings.clear
end
connected?(out_port, in_port) click to toggle source

Delegated call from {Port#connected?}

Always returns false as “plain” data service ports cannot be connected

# File lib/syskit/models/data_service.rb, line 261
def connected?(out_port, in_port)
    false
end
create_proxy_task() click to toggle source

Create a task that can be used as a placeholder for self in the plan

@return [TaskContext]

# File lib/syskit/models/data_service.rb, line 251
def create_proxy_task
    proxy_task_model.new
end
each_fullfilled_model() { |m| ... } click to toggle source

The set of services that this service provides

# File lib/syskit/models/data_service.rb, line 65
def each_fullfilled_model
    return enum_for(:each_fullfilled_model) if !block_given?
    ancestors.each do |m|
        if m.kind_of?(DataServiceModel)
            yield(m)
        end
    end
end
each_required_model() { |self| ... } click to toggle source
# File lib/syskit/models/data_service.rb, line 74
def each_required_model
    return enum_for(:each_required_model) if !block_given?
    yield(self)
end
if_already_present() click to toggle source

Optional dependency injection

Returns an {InstanceRequirements} that you can use to inject optional dependencies that will be fullfilled only if there is already a matching task deployed in the plan

This can only be meaningfully used when injected for a composition's optional child

@return [InstanceRequirements]

# File lib/syskit/models/data_service.rb, line 43
def if_already_present
    to_instance_requirements.if_already_present
end
instanciate(plan, context = DependencyInjectionContext.new, options = Hash.new, &block) click to toggle source

Create a task instance that can be used in a plan to represent this service

The returned task instance is obviously an abstract one

@return [TaskContext]

# File lib/syskit/models/data_service.rb, line 271
def instanciate(plan, context = DependencyInjectionContext.new, options = Hash.new, &block)
    proxy_task_model.instanciate(plan, context, options, &block)
end
port_mappings_for(service_type) click to toggle source

Returns the set of port mappings needed between service_type and self

In other words, if one wants to link port A from service_type on a task that provides a service of type self, it should actually link to

actual_port_name = (port_mappings_for(service_type)['A'] || 'A')

@raise [ArgumentError] if self does not provide service_type

# File lib/syskit/models/data_service.rb, line 141
def port_mappings_for(service_type)
    result = port_mappings[service_type]
    if !result
        raise ArgumentError, "#{service_type.short_name} is not provided by #{short_name}"
    end
    result
end
pretty_print(pp) click to toggle source
# File lib/syskit/models/data_service.rb, line 275
def pretty_print(pp)
    pp.text short_name
end
provides(service_model, new_port_mappings = Hash.new) click to toggle source

Declares that this data service model provides the given service model

If no port mappings are given, it will mean that the ports defined by service_model should be added to this service's interface. If port mappings are given, they define the mapping between ports in service_model and existing ports in self

Note that if both service_model and self have a port with the same name, this port needs also to be mapped explicitely by providing the 'name' => 'name' mapping in new_port_mappings

Calls superclass method
# File lib/syskit/models/data_service.rb, line 167
def provides(service_model, new_port_mappings = Hash.new)
    # A device can provide either a device or a data service, but
    # not a combus. Idem for data service: only other data services
    # can be provided
    if !kind_of?(service_model.class)
        raise ArgumentError, "a #{self.class.name} cannot provide a #{service_model.class.name}. If this is really what you mean, declare #{self.name} as a #{service_model.class.name} first"
    end

    if parent_models.include?(service_model)
        return
    elsif !service_model.kind_of?(DataServiceModel) # this is probably just a task service
        return super(service_model)
    end

    service_model.each_port do |p|
        if find_port(p.name) && !new_port_mappings[p.name]
            raise SpecError, "port collision: #{self} and #{service_model} both have a port named #{p.name}. If you mean to tell syskit that this is the same port, you must provide the mapping explicitely by adding '#{p.name}' => '#{p.name}' to the provides statement"
            new_port_mappings[p.name] ||= p.name
        end
    end

    new_port_mappings.each do |service_name, self_name|
        if !(source_port = service_model.find_port(service_name))
            raise SpecError, "#{service_name} is not a port of #{service_model.short_name}"
        end
        if !(target_port = find_port(self_name))
            raise SpecError, "#{self_name} is not a port of #{short_name}"
        end
        if target_port.type != source_port.type
            raise SpecError, "invalid port mapping #{service_name} => #{self_name} in #{self.short_name}.provides(#{service_model.short_name}): port #{source_port.name} on #{self.short_name} is of type #{source_port.type.name} and #{target_port.name} on #{service_model.short_name} is of type #{target_port.type.name}"
        elsif source_port.class != target_port.class
            raise SpecError, "invalid port mapping #{service_name} => #{self_name} in #{self.short_name}.provides(#{service_model.short_name}): port #{source_port.name} on #{self.short_name} is a #{target_port.class.name} and #{target_port.name} on #{service_model.short_name} is of a #{source_port.class.name}"
        end
    end

    service_model.port_mappings.each do |original_service, mappings|
        updated_mappings = Hash.new
        mappings.each do |from, to|
            updated_mappings[from] = new_port_mappings[to] || to
        end
        port_mappings[original_service] =
            Models.merge_port_mappings(port_mappings[original_service] || Hash.new, updated_mappings)
    end

    # Now, add the ports that are going to be created because of the
    # addition of the service
    service_model.each_port do |p|
        new_port_mappings[p.name] ||= p.name
    end
    port_mappings[service_model] =
        Models.merge_port_mappings(port_mappings[service_model] || Hash.new, new_port_mappings)

    # Merging the interface should never raise at this stage. It
    # should have been validated above.
    Models.merge_orogen_task_context_models(orogen_model, [service_model.orogen_model], new_port_mappings)

    # For completeness, add port mappings for ourselves
    port_mappings[self] = Hash.new
    each_port do |p|
        port_mappings[self][p.name] = p.name
    end

    super(service_model)
end
provides?(srv) click to toggle source

Tests whether self already provides another service

@param [Model<DataService>]

# File lib/syskit/models/data_service.rb, line 152
def provides?(srv)
    parent_models.include?(srv)
end
proxy_task_model() click to toggle source

A task model that can be used to represent an instance of this data service in a Roby plan

@return [Model<TaskContext>]

# File lib/syskit/models/data_service.rb, line 240
def proxy_task_model
    if @proxy_task_model
        return @proxy_task_model
    end
    @proxy_task_model = Syskit.proxy_task_model_for([self])
end
resolve(task) click to toggle source

Resolves a bound data service of this model from the given task

# File lib/syskit/models/data_service.rb, line 288
def resolve(task)
    if task = try_resolve(task)
        task
    else
        raise ArgumentError, "cannot resolve #{self} into #{task}"
    end
end
to_component_model() click to toggle source
# File lib/syskit/models/data_service.rb, line 255
def to_component_model; self end
to_dot(io) click to toggle source
# File lib/syskit/models/data_service.rb, line 296
def to_dot(io)
    id = object_id.abs
    inputs = orogen_model.all_input_ports.map(&:name)
    outputs = orogen_model.all_output_ports.map(&:name)
    label = Graphviz.dot_iolabel(constant_name, inputs, outputs)
    io << "  C#{id} [label=\"#{label}\",fontsize=15];"

    parent_models.each do |parent_m|
        parent_id = parent_m.object_id.abs
        (parent_m.each_input_port.to_a + parent_m.each_output_port.to_a).
            each do |parent_p|
            io << "  C#{parent_id}:#{parent_p.name} -> C#{id}:#{port_mappings_for(parent_m)[parent_p.name]};"
        end

    end
end
try_resolve(task) click to toggle source

Resolves a bound data service of this model from the given task

# File lib/syskit/models/data_service.rb, line 280
def try_resolve(task)
    begin
        task.find_data_service_from_type(self)
    rescue AmbiguousServiceSelection
    end
end