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
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
- Orocos::Spec::TaskContext
-
the object describing the data
service's interface
Public Class Methods
# 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
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
# File lib/syskit/models/data_service.rb, line 313 def as_plan to_instance_requirements.as_plan end
# 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
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 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
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
# 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
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
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
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
# File lib/syskit/models/data_service.rb, line 275 def pretty_print(pp) pp.text short_name end
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
# 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
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
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
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
# File lib/syskit/models/data_service.rb, line 255 def to_component_model; self end
# 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
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