00001
00002
00003
00004
00005 '''rtshell
00006
00007 Copyright (C) 2009-2014
00008 Geoffrey Biggs
00009 RT-Synthesis Research Group
00010 Intelligent Systems Research Institute,
00011 National Institute of Advanced Industrial Science and Technology (AIST),
00012 Japan
00013 All rights reserved.
00014 Licensed under the Eclipse Public License -v 1.0 (EPL)
00015 http://www.opensource.org/licenses/eclipse-1.0.txt
00016
00017 Base class for generated-on-demand components.
00018
00019 '''
00020
00021
00022 import inspect
00023 import OpenRTM_aist
00024 import RTC
00025 import sys
00026 import traceback
00027
00028
00029
00030
00031
00032 class Port(object):
00033 '''Class to store the objects used for a port.'''
00034 def __init__(self, data, port, formatter=None, raw_spec=None, *args,
00035 **kwargs):
00036 super(Port, self).__init__()
00037 self._data = data
00038 self._port = port
00039 self._formatter = formatter
00040 self._raw = raw_spec
00041 members = [m for m in dir(self.data) if not m.startswith('_')]
00042 if len(members) == 2 and 'tm' in members and \
00043 'data' in members and self.data.tm.__class__ == RTC.Time:
00044 self._standard_type = True
00045 else:
00046 self._standard_type = False
00047
00048 @property
00049 def data(self):
00050 '''Get the port's data reference.'''
00051 return self._data
00052
00053 @property
00054 def port(self):
00055 '''Get the port object.'''
00056 return self._port
00057
00058 @property
00059 def formatter(self):
00060 '''Get the formatter function for the port, if any.'''
00061 return self._formatter
00062
00063 @property
00064 def name(self):
00065 '''Get the port's name.'''
00066 return self._port.getName()
00067
00068 @property
00069 def raw(self):
00070 '''Get the raw port spec for this port, if any.'''
00071 return self._raw
00072
00073 @property
00074 def standard_type(self):
00075 '''Check if the port's data type is an RTC standard type.
00076
00077 RTC standard types have a tm member (the timestamp) and a data member
00078 (the data).
00079
00080 '''
00081 return self._standard_type
00082
00083 def read(self):
00084 '''Read the next value from the port into self.data.'''
00085 self._data = self._port.read()
00086
00087 def format(self):
00088 '''Return a string representation of the value of self.data.
00089
00090 If self.formatter is not None, that function will be called to create
00091 the string representation. Otherwise, str() will be used except in the
00092 cases of data that contains a .tm member of type RTC.Time and a .data
00093 member. In that case, the time will be pretty-printed, followed by the
00094 data member, printed using str().
00095
00096 '''
00097 if self.formatter:
00098 return self.formatter(self.data)
00099 else:
00100 members = [m for m in dir(self.data) if not m.startswith('_')]
00101 if len(members) == 2 and 'tm' in members and \
00102 'data' in members and self.data.tm.__class__ == RTC.Time:
00103 return '[{0}.{1:09}] {2}'.format(self.data.tm.sec,
00104 self.data.tm.nsec, self.data.data)
00105 else:
00106 return str(self.data)
00107
00108
00109
00110
00111
00112 class GenComp(OpenRTM_aist.DataFlowComponentBase):
00113 def __init__(self, mgr, port_specs, event=None, max=-1, *args, **kwargs):
00114 '''Constructor.
00115
00116 @param mgr Reference to the manager that created this component.
00117 @param port_spec The port layout of the component. This must be
00118 a list of port_types.PortSpec objects.
00119 @param event An event object that can be .set() to indicate
00120 that the component has finished its assigned task
00121 and should be shut down.
00122 @param max The maximum number of times this component should
00123 perform its onExecute function before setting the
00124 event to request a shutdown. Defaults to -1, for
00125 unlimited.
00126
00127 '''
00128 OpenRTM_aist.DataFlowComponentBase.__init__(self, mgr)
00129 self._port_specs = port_specs
00130 self._event = event
00131 self._max = max
00132 self._count = 0
00133
00134 def onInitialize(self):
00135 try:
00136 self._ports = {}
00137 for p in self._port_specs:
00138 args, varargs, varkw, defaults = \
00139 inspect.getargspec(p.type.__init__)
00140 if defaults:
00141 init_args = tuple([None \
00142 for ii in range(len(args) - len(defaults) - 1)])
00143 else:
00144 init_args = [None for ii in range(len(args) - 1)]
00145 if p.input:
00146 port_con = OpenRTM_aist.InPort
00147 port_reg = self.registerInPort
00148 else:
00149 port_con = OpenRTM_aist.OutPort
00150 port_reg = self.registerOutPort
00151 p_data = p.type(*init_args)
00152 p_port = port_con(p.name, p_data)
00153 port_reg(p.name, p_port)
00154 self._ports[p.name] = Port(p_data, p_port,
00155 formatter=p.formatter, raw_spec=p)
00156 except:
00157 print >>sys.stderr, traceback.format_exc()
00158 return RTC.RTC_ERROR
00159 return RTC.RTC_OK
00160
00161 def onExecute(self, ec_id):
00162
00163 res = RTC.RTC_OK
00164 if self._count < self._max or self._max < 0:
00165 res, executed = self._behv(ec_id)
00166 if executed > 0:
00167 self._count += executed
00168 if self._max > -1 and self._count >= self._max:
00169 self._set()
00170 return res
00171
00172 def _behv(self, ec_id):
00173 '''Behaviour function for derived components.
00174
00175 Deriving classes must implement this function. It will be called by
00176 onExecute. It must return a tuple of (RTC result code, _behv result
00177 value). The RTC result code is used to create the result of onExecute;
00178 if no errors occur, it must be RTC.RTC_OK. The _behv result code is
00179 used to tell the component if the behaviour was able to execute
00180 (whether it succeeded or not), for the purposes of execution counting.
00181 It should be the number of iterations executed.
00182
00183 '''
00184 pass
00185
00186 def _set(self):
00187 '''Call set() on the event object to notify waiters.'''
00188 if self._event:
00189 self._event.set()
00190
00191
00192 def make_factory(cons, port_specs, event=None, max=-1, **kwargs):
00193 def fact_fun(mgr):
00194 return cons(mgr, port_specs, event=event, max=max, **kwargs)
00195 return fact_fun
00196
00197
00198 def make_init(name, cons, port_specs, event=None, rate=1.0, max=-1, **kwargs):
00199 def init_fun(mgr):
00200 spec= ['implementation_id', name,
00201 'type_name', name,
00202 'description', 'rtshell generated-on-demand component.',
00203 'version', '3.0',
00204 'vendor', 'rtshell',
00205 'category', 'Generated',
00206 'activity_type', 'DataFlowComponent',
00207 'max_instance', '1',
00208 'language', 'Python',
00209 'lang_type', 'SCRIPT',
00210 '']
00211 profile = OpenRTM_aist.Properties(defaults_str=spec)
00212 mgr.registerFactory(profile,
00213 make_factory(cons, port_specs, event=event, max=max, **kwargs),
00214 OpenRTM_aist.Delete)
00215 comp = mgr.createComponent(name +
00216 '?exec_cxt.periodic.type=PeriodicExecutionContext&'
00217 'exec_cxt.periodic.rate={0}'.format(rate))
00218 return init_fun
00219