class Orocos::TaskContext
A proxy for a remote task context. The communication between Ruby and the RTT component is done through the CORBA transport.
See README.txt for information on how you can manipulate a task context through this class.
The available information about this task context can be displayed using Ruby's pretty print library:
require 'pp' pp task_object
Attributes
The logger task that should be used to log data that concerns this task
@return [#log]
Public Class Methods
VALUE task_context_create(int argc, VALUE *argv,VALUE klass)
{
corba_must_be_initialized();
// all parametes are forwarded to ruby initialize
if(argc < 1)
rb_raise(rb_eArgError, "no ior given");
std::string ior(StringValueCStr(argv[0]));
RTaskContext *context = corba_blocking_fct_call_with_result(boost::bind(&CorbaAccess::createRTaskContext,CorbaAccess::instance(),ior));
VALUE obj = simple_wrap(klass, context);
rb_obj_call_init(obj,argc,argv);
return obj;
}
A new TaskContext instance representing the remote task context with the given IOR
If a remote task is only known by its name use {Orocos.name_service} to create an handle to the remote task.
@param [String] ior The IOR of the remote task. @param [Hash] options The options. @option options [String] :name Overwrites the real name of remote task @option options [Orocos::Process] :process The process supporting the task @option options [String] :namespace The namespace of the task
# File lib/orocos/task_context.rb, line 135 def initialize(ior, name: do_real_name, model: nil, **other_options) super(name, model: model, **other_options) @ior = ior if process && (process.default_logger_name != name) self.logger = process.default_logger end end
# File lib/orocos/task_context.rb, line 86 def self.state_transition_call(m, expected_state, target_state) class_eval " def #{m}(wait_for_completion = true, polling = 0.05) if wait_for_completion current_state = peek_current_state end CORBA.refine_exceptions(self) do begin do_#{m} rescue Orocos::StateTransitionFailed => e current_state = rtt_state reason = if current_state == :EXCEPTION ". The task is in an exception state. You must call #reset_exception before trying again" elsif current_state == :PRE_OPERATIONAL && '#{m}' == 'start' ". The Task must be configured before it could started. Did you forgot to call configure on the task?" elsif current_state != :#{expected_state} ". Tasks must be in #{expected_state} state before calling #{m}, but was in \#{current_state}" end raise e, "\#{e.message} the '\#{self.name}' task\#{ " of type \#{self.model.name}" if self.model}\#{reason}", e.backtrace end end if wait_for_completion while current_state == peek_current_state#{" && current_state != :#{target_state}" if target_state} sleep polling end end end ", __FILE__, (__LINE__ + 1) end
Public Instance Methods
static VALUE task_context_equal_p(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cTaskContext))
return Qfalse;
RTaskContext& self_ = get_wrapped<RTaskContext>(self);
RTaskContext& other_ = get_wrapped<RTaskContext>(other);
return self_.task->_is_equivalent(other_.task) ? Qtrue : Qfalse;
}
Applies the TaskContext configuration stored by the main configuration manager to the TaskContext
See also load_conf and #Orocos.load_config_dir
# File lib/orocos/task_context.rb, line 305 def apply_conf(section_names = Array.new, override=false) Orocos.conf.apply(self, section_names, override) end
Loads the configuration for the TaskContext from a file, into the main configuration manager and applies it to the TaskContext
See also apply_conf and #Orocos.load_config_dir
# File lib/orocos/task_context.rb, line 292 def apply_conf_file(file,section_names=Array.new,override=false) Orocos.conf.load_file(file,model.name) apply_conf(section_names,override) end
Returns an Attribute object representing the given attribute
Raises NotFound if no such attribute exists.
Attributes can also be read and written by calling directly the relevant method on the task context:
task.attribute("myProperty").read task.attribute("myProperty").write(value)
is equivalent to
task.myProperty task.myProperty = value
# File lib/orocos/task_context.rb, line 436 def attribute(name) name = name.to_s if a = attributes[name] if has_attribute?(name) return a else attributes.delete(name) raise Orocos::InterfaceObjectNotFound.new(self, name), "task #{self.name} does not have an attribute named #{name}", e.backtrace end end type_name = CORBA.refine_exceptions(self) do begin do_attribute_type_name(name) rescue ArgumentError => e raise Orocos::InterfaceObjectNotFound.new(self, name), "task #{self.name} does not have an attribute named #{name}", e.backtrace end end a = Attribute.new(self, name, type_name) if configuration_log create_property_log_stream(a) a.log_current_value end attributes[name] = a end
Returns the array of the names of available attributes on this task context
# File lib/orocos/task_context.rb, line 415 def attribute_names CORBA.refine_exceptions(self) do do_attribute_names end end
Calls the required operation with the given argument
This is a shortcut for operation(name).calldop(*arguments)
# File lib/orocos/task_context.rb, line 579 def callop(name, *args) operation(name).callop(*args) end
Cleans the component, i.e. do the transition from STATE_STOPPED into STATE_PRE_OPERATIONAL.
Raises StateTransitionFailed if the component was not in STATE_STOPPED state before the call. The component cannot refuse to perform the transition (but can take an arbitrarily long time to do it).
# File lib/orocos/task_context.rb, line 367 state_transition_call :cleanup, 'STOPPED', 'PRE_OPERATIONAL'
Configures the component, i.e. do the transition from STATE_PRE_OPERATIONAL into STATE_STOPPED.
Raises StateTransitionFailed if the component was not in STATE_PRE_OPERATIONAL state before the call, or if the component refused to do the transition (startHook() returned false)
# File lib/orocos/task_context.rb, line 323 state_transition_call :configure, 'PRE_OPERATIONAL', 'STOPPED'
# File lib/orocos/task_context.rb, line 625 def connect_to(sink, policy = Hash.new) port = find_output_port(sink.type, nil) if !port raise ArgumentError, "port #{sink.name} does not match any output port of #{name}" end port.connect_to(sink, policy) end
# File lib/orocos/task_context.rb, line 251 def create_property_log_stream(p) stream_name = "#{self.name}.#{p.name}" if !configuration_log.has_stream?(stream_name) p.log_stream = configuration_log.create_stream(stream_name, p.type, p.log_metadata) else p.log_stream = configuration_log.stream(stream_name) end end
# File lib/orocos/task_context.rb, line 633 def disconnect_from(sink, policy = Hash.new) each_output_port do |out_port| if out_port.type == sink.type out_port.disconnect_from(sink) end end nil end
static VALUE task_context_attribute_names(VALUE self)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
VALUE result = rb_ary_new();
RTT::corba::CConfigurationInterface::CAttributeNames_var names =
corba_blocking_fct_call_with_result(bind(&_objref_CConfigurationInterface::getAttributeList,(_objref_CConfigurationInterface*)context.main_service));
for (unsigned int i = 0; i != names->length(); ++i)
{
#if RTT_VERSION_GTE(2,9,0)
CORBA::String_var name = names[i].name;
#else
CORBA::String_var name = names[i];
#endif
rb_ary_push(result, rb_str_new2(name));
}
return result;
}
static VALUE task_context_attribute_type_name(VALUE self, VALUE name)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
std::string const expected_name = StringValuePtr(name);
CORBA::String_var attribute_type_name =
corba_blocking_fct_call_with_result(bind(&_objref_CConfigurationInterface::getAttributeTypeName,(_objref_CConfigurationInterface*)context.main_service,StringValuePtr(name)));
std::string type_name = std::string(attribute_type_name);
if (type_name != "na")
return rb_str_new(type_name.c_str(), type_name.length());
rb_raise(rb_eArgError, "no such attribute %s", StringValuePtr(name));
return Qfalse;
}
static VALUE task_context_cleanup(VALUE task)
{
return call_checked_state_change(task, "failed to cleanup", &RTT::corba::_objref_CTaskContext::cleanup);
}
static VALUE task_context_configure(VALUE task)
{
return call_checked_state_change(task, "failed to configure", &RTT::corba::_objref_CTaskContext::configure);
}
static VALUE task_context_has_operation_p(VALUE self, VALUE name)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
corba_blocking_fct_call(bind(&_objref_COperationInterface::getResultType,(_objref_COperationInterface*)context.main_service,StringValuePtr(name)));
return Qtrue;
}
static VALUE task_context_has_port_p(VALUE self, VALUE name)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
corba_blocking_fct_call(bind(&_objref_CDataFlowInterface::getPortType,(CDataFlowInterface_ptr)context.ports,StringValuePtr(name)));
return Qtrue;
}
static VALUE task_context_operation_names(VALUE self)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
VALUE result = rb_ary_new();
#if RTT_VERSION_GTE(2,9,0)
RTT::corba::COperationInterface::COperationDescriptions_var names =
corba_blocking_fct_call_with_result(bind(&_objref_COperationInterface::getOperations,(_objref_COperationInterface*)context.main_service));
#else
RTT::corba::COperationInterface::COperationList_var names =
corba_blocking_fct_call_with_result(bind(&_objref_COperationInterface::getOperations,(_objref_COperationInterface*)context.main_service));
#endif
for (unsigned int i = 0; i != names->length(); ++i)
{
#if RTT_VERSION_GTE(2,9,0)
CORBA::String_var name = names[i].name;
#else
CORBA::String_var name = names[i];
#endif
rb_ary_push(result, rb_str_new2(name));
}
return result;
}
static VALUE task_context_do_port(VALUE self, VALUE name, VALUE model)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
RTT::corba::CPortType port_type;
CORBA::String_var type_name;
port_type = corba_blocking_fct_call_with_result(bind(&_objref_CDataFlowInterface::getPortType,(_objref_CDataFlowInterface*)context.ports,StringValuePtr(name)));
type_name = corba_blocking_fct_call_with_result(bind(&_objref_CDataFlowInterface::getDataType,(_objref_CDataFlowInterface*)context.ports,StringValuePtr(name)));
VALUE obj = Qnil;
VALUE args[4] = { self, rb_str_dup(name), rb_str_new2(type_name), model };
if (port_type == RTT::corba::CInput)
obj = rb_class_new_instance(4, args, cInputPort);
else if (port_type == RTT::corba::COutput)
obj = rb_class_new_instance(4, args, cOutputPort);
return obj;
}
static VALUE task_context_port_names(VALUE self)
{
VALUE result = rb_ary_new();
RTaskContext& context = get_wrapped<RTaskContext>(self);
RTT::corba::CDataFlowInterface::CPortNames_var ports =
corba_blocking_fct_call_with_result(bind(&_objref_CDataFlowInterface::getPorts,(_objref_CDataFlowInterface*)context.ports));
for (unsigned int i = 0; i < ports->length(); ++i)
rb_ary_push(result, rb_str_new2(ports[i]));
return result;
}
static VALUE task_context_property_names(VALUE self)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
VALUE result = rb_ary_new();
RTT::corba::CConfigurationInterface::CPropertyNames_var names =
corba_blocking_fct_call_with_result(bind(&_objref_CConfigurationInterface::getPropertyList,(_objref_CConfigurationInterface*)context.main_service));
for (unsigned int i = 0; i != names->length(); ++i)
{
CORBA::String_var name = names[i].name;
rb_ary_push(result, rb_str_new2(name));
}
return result;
}
static VALUE task_context_property_type_name(VALUE self, VALUE name)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
std::string const expected_name = StringValuePtr(name);
CORBA::String_var attribute_type_name =
corba_blocking_fct_call_with_result(bind(&_objref_CConfigurationInterface::getPropertyTypeName,(_objref_CConfigurationInterface*)context.main_service,StringValuePtr(name)));
std::string type_name = std::string(attribute_type_name);
if (type_name != "na")
return rb_str_new(type_name.c_str(), type_name.length());
rb_raise(rb_eArgError, "no such property %s", StringValuePtr(name));
return Qfalse;
}
static VALUE task_context_real_name(VALUE self)
{
RTaskContext& context = get_wrapped<RTaskContext>(self);
return rb_str_new2(context.name.c_str());
}
static VALUE task_context_reset_exception(VALUE task)
{
return call_checked_state_change(task, "failed to transition from the Exception state to Stopped", &RTT::corba::_objref_CTaskContext::resetException);
}
static VALUE task_context_start(VALUE task)
{
return call_checked_state_change(task, "failed to start", &RTT::corba::_objref_CTaskContext::start);
}
static VALUE task_context_state(VALUE task)
{
RTaskContext& context = get_wrapped<RTaskContext>(task);
return INT2FIX(corba_blocking_fct_call_with_result(boost::bind(&_objref_CTaskContext::getTaskState,(CTaskContext_ptr)context.task)));
}
static VALUE task_context_stop(VALUE task)
{
return call_checked_state_change(task, "failed to stop", &RTT::corba::_objref_CTaskContext::stop);
}
Returns true if this task context has a command with the given name
# File lib/orocos/task_context.rb, line 370 def has_operation?(name) name = name.to_s CORBA.refine_exceptions(self) do begin do_has_operation?(name) rescue Orocos::NotFound false end end end
Returns true if this task context has a port with the given name
# File lib/orocos/task_context.rb, line 382 def has_port?(name) name = name.to_s CORBA.refine_exceptions(self) do begin do_has_port?(name) rescue Orocos::NotFound false end end end
Tell the task to use the given Pocolog::Logfile object to log all changes to its properties
# File lib/orocos/task_context.rb, line 262 def log_all_configuration(logfile) @configuration_log = logfile each_property do |p| create_property_log_stream(p) p.log_current_value end end
Connects all ports of the task with the logger of the deployment @param [Hash] options option hash to exclude specific ports @option options [String,Array<String>] :exclude_ports The name of the excluded ports @return [Set<String,String>] Sets of task and port names
@example logging all ports beside a port called frame task.log_all_ports(:exclude_ports => “frame”)
# File lib/orocos/task_context.rb, line 238 def log_all_ports(options = Hash.new) # Right now, the only allowed option is :exclude_ports options, logger_options = Kernel.filter_options options,:exclude_ports => nil exclude_ports = Array(options[:exclude_ports]) logger_options[:tasks] = Regexp.new(basename) ports = Orocos.log_all_process_ports(process,logger_options) do |port| !exclude_ports.include? port.name end raise "#{name}: no ports were selected for logging" if ports.empty? ports end
Returns the Orogen specification object for this task's model. It will return a default model if the remote task does not respond to getModelName or the description file cannot be found.
See also info
# File lib/orocos/task_context.rb, line 595 def model model = super if model return model end model_name = begin self.getModelName rescue NoMethodError nil end self.model = if !model_name if name !~ /.*orocosrb_(\d+)$/ Orocos.warn "#{name} is a task context not generated by orogen, using default task model" end Orocos.create_orogen_task_context_model(name) elsif model_name.empty? Orocos.create_orogen_task_context_model else begin Orocos.default_loader.task_model_from_name(model_name) rescue OroGen::NotFound Orocos.warn "#{name} is a task context of class #{model_name}, but I cannot find the description for it, falling back" Orocos.create_orogen_task_context_model(model_name) end end end
Returns an Operation object that represents the given method on the remote component.
Raises NotFound if no such operation exists.
# File lib/orocos/task_context.rb, line 564 def operation(name) name = name.to_s CORBA.refine_exceptions(self) do return_types = operation_return_types(name) arguments = operation_argument_types(name) Operation.new(self, name, return_types, arguments) end rescue Orocos::NotFound => e raise Orocos::InterfaceObjectNotFound.new(self, name), "task #{self.name} does not have an operation named #{name}", e.backtrace end
Returns the array of the names of available operations on this task context
# File lib/orocos/task_context.rb, line 395 def operation_names CORBA.refine_exceptions(self) do do_operation_names.each do |str| str.force_encoding('ASCII') if str.respond_to?(:force_encoding) end end end
Reads all state transitions that have been announced by the task and pushes them to @state_queue
The following call to state will first look at @state_queue before accessing the task context
# File lib/orocos/task_context.rb, line 195 def peek_state if model && model.extended_state_support? if !@state_reader || !@state_reader.connected? @state_reader = state_reader @state_queue << rtt_state end while new_state = @state_reader.read_new @state_queue << new_state end else super end @state_queue end
# File lib/orocos/task_context.rb, line 144 def ping rtt_state nil end
Returns an object that represents the given port on the remote task context. The returned object is either an InputPort or an OutputPort
Raises NotFound if no such port exists.
Ports can also be accessed by calling directly the relevant method on the task context:
task.port("myPort")
is equivalent to
task.myPort
# File lib/orocos/task_context.rb, line 534 def port(name, verify = true) name = name.to_str CORBA.refine_exceptions(self) do if @ports[name] if !verify || has_port?(name) # Check that this port is still valid @ports[name] else @ports.delete(name) raise NotFound, "no port named '#{name}' on task '#{self.name}'" end else @ports[name] = raw_port(name) end end end
Returns the names of all the ports defined on this task context
# File lib/orocos/task_context.rb, line 552 def port_names CORBA.refine_exceptions(self) do do_port_names.each do |str| str.force_encoding('ASCII') if str.respond_to?(:force_encoding) end end end
Returns a Property object representing the given property
Raises NotFound if no such property exists.
Ports can also be accessed by calling directly the relevant method on the task context:
task.property("myProperty").read task.property("myProperty").write(value)
is equivalent to
task.myProperty task.myProperty = value
# File lib/orocos/task_context.rb, line 490 def property(name) name = name.to_s if p = properties[name] if has_property?(name) return p else properties.delete(name) raise Orocos::InterfaceObjectNotFound.new(self, name), "task #{self.name} does not have a property named #{name}", e.backtrace end end p = raw_property(name) if configuration_log create_property_log_stream(p) p.log_current_value end properties[name] = p end
Returns the array of the names of available properties on this task context
# File lib/orocos/task_context.rb, line 405 def property_names CORBA.refine_exceptions(self) do do_property_names.each do |str| str.force_encoding('ASCII') if str.respond_to?(:force_encoding) end end end
@api private
Resolve a Port object for the given port name
# File lib/orocos/task_context.rb, line 512 def raw_port(name) port_model = model.find_port(name) do_port(name, port_model) rescue Orocos::NotFound => e raise Orocos::InterfaceObjectNotFound.new(self, name), "task #{self.name} does not have a port named #{name}", e.backtrace end
Return the property object without caching nor validation
# File lib/orocos/task_context.rb, line 464 def raw_property(name) type_name = CORBA.refine_exceptions(self) do begin do_property_type_name(name) rescue ArgumentError => e raise Orocos::InterfaceObjectNotFound.new(self, name), "task #{self.name} does not have a property named #{name}", e.backtrace end end Property.new(self, name, type_name) end
Recover from the exception state. It does the transition from STATE_EXCEPTION to either STATE_STOPPED if the component does not need any configuration or STATE_PRE_OPERATIONAL otherwise
Raises StateTransitionFailed if the component was not in a proper state before the call.
# File lib/orocos/task_context.rb, line 345 state_transition_call :reset_exception, 'EXCEPTION', nil
# File lib/orocos/task_context.rb, line 642 def resolve_connection_from(source, policy = Hash.new) port = find_input_port(source.type,nil) if !port raise ArgumentError, "port #{source.name} does not match any input port of #{name}." end source.connect_to(port, policy) end
# File lib/orocos/task_context.rb, line 650 def resolve_disconnection_from(source) each_input_port do |in_port| if in_port.type == source.type source.disconnect_from(in_port) end end nil end
Reads the state announced by the task's getState() operation
# File lib/orocos/task_context.rb, line 226 def rtt_state value = CORBA.refine_exceptions(self) { do_state() } @state_symbols[value] end
Saves the current configuration into a file
# File lib/orocos/task_context.rb, line 310 def save_conf(file, section_names = nil) Orocos.conf.save(self,file,section_names) end
Sends the required operation with the given argument
This is a shortcut for operation(name).sendop(*arguments)
# File lib/orocos/task_context.rb, line 586 def sendop(name, *args) operation(name).sendop(*args) end
Starts the component, i.e. do the transition from STATE_STOPPED into STATE_RUNNING.
Raises StateTransitionFailed if the component was not in STATE_STOPPED state before the call, or if the component refused to do the transition (startHook() returned false)
# File lib/orocos/task_context.rb, line 334 state_transition_call :start, 'STOPPED', 'RUNNING'
Returns a StateReader object that allows to flexibly monitor the task's state
# File lib/orocos/task_context.rb, line 181 def state_reader(policy = Hash.new) policy = Port.prepare_policy({:init => true, :type => :buffer, :size => 10}.merge(policy)) reader = port('state').reader(policy) reader.extend StateReader reader.state_symbols = @state_symbols reader end
Stops the component, i.e. do the transition from STATE_RUNNING into STATE_STOPPED.
Raises StateTransitionFailed if the component was not in STATE_RUNNING state before the call. The component cannot refuse to perform the transition (but can take an arbitrarily long time to do it).
# File lib/orocos/task_context.rb, line 356 state_transition_call :stop, 'RUNNING', 'STOPPED'
Returns the PID of the thread this task runs on
This is available only on oroGen task, for which oroGen adds an orogen_getPID operation that returns this information
# File lib/orocos/task_context.rb, line 214 def tid if !@tid if has_operation?('__orogen_getTID') @tid = operation('__orogen_getTID').callop() else raise ArgumentError, "#tid is available only on oroGen tasks, not #{self}" end end @tid end
# File lib/orocos/async/orocos.rb, line 79 def to_async(options = Hash.new) options[:name] ||= name options[:ior] ||= ior Orocos::Async::CORBA::TaskContext.new(options) end
# File lib/orocos/async/orocos.rb, line 85 def to_proxy(options = Hash.new) options[:use] ||= to_async # use name service to check if there is already # a proxy for the task Orocos::Async.proxy(name,options) end
# File lib/orocos/task_context.rb, line 297 def to_s "#<TaskContext: #{self.class.name}/#{name}>" end
Waits for the task to be in state state_name for the specified
amount of time
Raises RuntimeError on timeout
# File lib/orocos/task_context.rb, line 274 def wait_for_state(state_name, timeout = nil, polling = 0.1) state_name = state_name.to_sym start = Time.now peek_state while !@state_queue.include?(state_name) if timeout && (Time.now - start) > timeout raise "timing out while waiting for #{self} to be in state #{state_name}. It currently is in state #{current_state}" end sleep polling peek_state end end