class Orocos::Async::TaskContextBase

Public Class Methods

new(name,options=Hash.new) click to toggle source
Calls superclass method Orocos::Async::ObjectBase.new
# File lib/orocos/async/task_context_base.rb, line 60
def initialize(name,options=Hash.new)
    event_loop,reachable_options = Kernel.filter_options options,:event_loop => Orocos::Async.event_loop
    super(name,event_loop[:event_loop])
    @mutex = Mutex.new
    @last_state = nil
    @port_names = Array.new
    @property_names = Array.new
    @attribute_names = Array.new

    watchdog_proc = Proc.new do
        ping # call a method which raises ComError if the connection died
        # this is used to disconnect the task by an error handler
        [states,port_names,property_names,attribute_names]
    end

    @watchdog_timer = @event_loop.async_every(watchdog_proc,{:period => default_period,
                                              :default => [[],[],[],[]],
                                              :start => false,
                                              :sync_key => nil, #is blocked by the methods call ping, states, etc
                                              :known_errors => Orocos::Async::KNOWN_ERRORS}) do |data,error|
                                                    process_states(data[0])
                                                    process_port_names(data[1])
                                                    process_property_names(data[2])
                                                    process_attribute_names(data[3])
                                              end
    @watchdog_timer.doc = name
    reachable!(reachable_options)
end
to_ruby(task) click to toggle source

Creates a {RubyTasks::TaskContext} on which all values passed to the given task should be mirrored

@return [RubyTasks::TaskContext]

# File lib/orocos/async/task_context_base.rb, line 21
def self.to_ruby(task)
    begin
        t = Orocos::CORBA.name_service.get(task.basename)
        raise "Cannot create ruby task for #{task.name} "\
            "because there is already a task #{t.name} "\
            "registered on the main CORBA name service."
    rescue Orocos::NotFound
    end
    t = Orocos::RubyTasks::TaskContext.new(task.basename)
    task.on_port_reachable do |port|
        next if t.has_port?(port)
        port = task.port(port)
        port.wait
        p = t.create_output_port(port.name,port.type)
        port.on_data do |data|
            p.write data
        end
    end
    task.on_property_reachable do |prop|
        next if task.has_property?(prop)
        prop = task.property(prop)
        prop.wait
        p = @ruby_task_context.create_property(prop.name,prop.type)
        p.write p.new_sample.zero!
        prop.on_change do |data|
            p.write data
        end
    end
    t.configure
    t.start
    t
end

Public Instance Methods

attribute(name,options = Hash.new,&block) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 294
def attribute(name,options = Hash.new,&block)
    call_with_async(:orig_attribute,block,options,name)
end
call_with_async(method_name,user_callback,to_async_options,*args) click to toggle source

Helper method to setup async calls

Asynchronous calls can be called either with a callback or without. In the first case, the callback gets called later and the method returns right aways, otherwise the method get synchronously called. For synchronization reasons, even the synchronous call goes through the event loop (since the event loop avoids reentrant calls using the sync key).

This method is the common setup for this scheme. It uses the fact that all non-async objects must provide a to_async call to create a corresponding asynchronous-access object.

@param [Symbol] method_name the method that should be called @param [Proc,nil] user_callback the user-provided callback if there is

one

@param [Hash] to_async_options the options that should be passed to

to_async

@param [Array] the arguments that should be forwarded to the underlying

method

@return [Object] in the synchronous case, the method returns the

underlying method's return value. In the asynchronous case TODO
# File lib/orocos/async/task_context_base.rb, line 273
def call_with_async(method_name,user_callback,to_async_options,*args)
    p = proc do |object,error|
        async_object = object.to_async(Hash[:use => self].merge(to_async_options))
        if user_callback
            if user_callback.arity == 2
                user_callback.call(async_object,error)
            else
                user_callback.call(async_object)
            end
        else
            async_object
        end
    end
    if user_callback
        send(method_name,*args,&p)
    else
        async_object = send(method_name,*args)
        p.call async_object,nil
    end
end
clear_interface() click to toggle source
# File lib/orocos/async/task_context_base.rb, line 232
def clear_interface
    process_port_names
    process_attribute_names
    process_property_names
end
configure_delegation(configure_options = Hash.new) click to toggle source

Called by reachable! to do subclass-specific configuration

@param [Hash] configure_options all options passed to reachable! that

are not understood by #reachable!
# File lib/orocos/async/task_context_base.rb, line 200
def configure_delegation(configure_options = Hash.new)
end
each_attribute { |a| ... } → task click to toggle source

Enumerates the attributes that are available on this task, as instances of Orocos::Attribute

# File lib/orocos/async/task_context_base.rb, line 326
def each_attribute(&block)
    if !block_given?
        return enum_for(:each_attribute)
    end
    attribute_names.each do |name|
        yield(attribute(name))
    end
    self
end
each_port { |p| ... } → task click to toggle source

Enumerates the ports that are available on this task, as instances of either Orocos::InputPort or Orocos::OutputPort

# File lib/orocos/async/task_context_base.rb, line 341
def each_port(&block)
    if !block_given?
        return enum_for(:each_port)
    end
    port_names.each do |name|
        yield(port(name))
    end
    self
end
each_property { |a| ... } → task click to toggle source

Enumerates the properties that are available on this task, as instances of Orocos::Attribute

# File lib/orocos/async/task_context_base.rb, line 311
def each_property(&block)
    if !block_given?
        return enum_for(:each_property)
    end
    property_names.each do |name|
        yield(property(name))
    end
    self
end
name() click to toggle source
# File lib/orocos/async/task_context_base.rb, line 146
def name
    @mutex.synchronize do
        @name.dup if @name
    end
end
port(name, verify = true,options=Hash.new, &block) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 302
def port(name, verify = true,options=Hash.new, &block)
    call_with_async(:orig_port,block,options,name,verify)
end
property(name,options = Hash.new,&block) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 298
def property(name,options = Hash.new,&block)
    call_with_async(:orig_property,block,options,name)
end
reachable!(options = Hash.new) click to toggle source

Initiates the binding of the underlying sychronous access object to this async object.

It can either be directly given an object, or be asked to (asynchronously) query it.

@option options [Boolean] watchdog (true) if true, start a watchdog

timer that monitors the availability of the task context

@option options [Float] period (default_period) the period for the

watchdog (if enabled)

@option options [Boolean] wait (false) if true, reachable! will return

only when the task has successfully been found

@option options [Object] use (nil) if set, this is the object we will

use as underlying sychronous object. Otherwise, #task_context is
going to be used to find it.

@option options [Boolean] raise (false) if set, the task_context

method will raise if the task context cannot be accessed on first
try. Otherwise, it will try to access it forever until it finds it.
# File lib/orocos/async/task_context_base.rb, line 170
def reachable!(options = Hash.new)
    @mutex.synchronize do
        options, configure_options = Kernel.filter_options options,
            :watchdog => true,
            :period => default_period,
            :wait => false,
            :use => nil,
            :raise => false

        self.raise_on_access_error = options[:raise]

        if options[:use]
            @delegator_obj = options[:use]
            @watchdog_timer.doc = @delegator_obj.name
        else
            invalidate_delegator!
        end

        configure_delegation(configure_options)

        @watchdog_timer.start(options[:period],false) if options[:watchdog]
        @event_loop.async(method(:task_context))
    end
    wait if options[:wait]
end
reachable?(&block) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 238
def reachable?(&block)
    if block
        ping(&block)
    else
        ping
    end
    true
rescue Orocos::NotFound,Orocos::ComError => e
    unreachable!(:error => e)
    false
end
really_add_listener(listener) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 115
def really_add_listener(listener)
    return super unless listener.use_last_value?

    # call new listeners with the current value
    # to prevent different behaviors depending on
    # the calling order
    if listener.event == :port_reachable
        names = @port_names.dup
        event_loop.once do 
            names.each do |name|
                listener.call name
            end
        end
    elsif listener.event == :property_reachable
        names = @property_names.dup
        event_loop.once do
            names.each do |name|
                listener.call name
            end
        end
    elsif listener.event == :attribute_reachable
        names = @attribute_names.dup
        event_loop.once do
            names.each do |name|
                listener.call name
            end
        end
    end
    super
end
ruby_task_context?() click to toggle source

Tests whether a mirroring task has been created with {ruby_task_context}

@return [Boolean]

# File lib/orocos/async/task_context_base.rb, line 111
def ruby_task_context?
    !!@ruby_task_context
end
to_async(options=Hash.new) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 89
def to_async(options=Hash.new)
    self
end
to_proxy(options=Hash.new) click to toggle source
# File lib/orocos/async/task_context_base.rb, line 93
def to_proxy(options=Hash.new)
    Orocos::Async.proxy(name,options)
end
to_ruby() click to toggle source

Create a ruby task on which all received data is mirrored

This task context is unique, i.e. the same object will be returned by subsequent calls to this method.

@return [RubyTasks::TaskContext]

# File lib/orocos/async/task_context_base.rb, line 103
def to_ruby
    @ruby_task_context ||= TaskContextBase.to_ruby(self)
end
unreachable!(options = Hash.new) click to toggle source

Disconnectes self from the remote task context and returns its underlying object used to communicate with the remote task (designated object).

Returns nil if the TaskContext is not connected. Returns an EventLoop Event if not called from the event loop thread.

@param [Exception] reason The reason for the disconnect @return [Orocos::TaskContext,nil,Utilrb::EventLoop::Event]

# File lib/orocos/async/task_context_base.rb, line 211
def unreachable!(options = Hash.new)
    options = Kernel.validate_options options, :error
    # ensure that this is always called from the
    # event loop thread
    @event_loop.call do
        old_task = @mutex.synchronize do
            if valid_delegator?
                @access_error = options.delete(:error) ||
                    ArgumentError.new("cannot access the remote task context for an unknown reason")
                task = @delegator_obj
                invalidate_delegator!
                @watchdog_timer.cancel if @watchdog_timer
                task
            end
        end
        clear_interface
        event :unreachable if old_task
        old_task
    end
end