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 Classes and functions for managing port types.
00018
00019 '''
00020
00021
00022 import re
00023 import rtctree.path
00024
00025 import comp_mgmt
00026 import fmt
00027 import rts_exceptions
00028
00029
00030
00031
00032
00033 class PortSpec(object):
00034 def __init__(self, name, type, target, input=True, formatter=None,
00035 type_name='', raw='', *args, **kwargs):
00036 super(PortSpec, self).__init__()
00037 self._formatter = formatter
00038 self._input = input
00039 self._name = name
00040 self._raw_specs = [raw]
00041 self._targets = [target]
00042 self._type = type
00043 self._type_name = type_name
00044
00045 def __str__(self):
00046 if self._formatter:
00047 fmt_str = '#{0}'.format(self._formatter)
00048 else:
00049 fmt_str = ''
00050 result = ''
00051 for t in self._targets:
00052 result += '{0}.{1}{2},'.format(rtctree.path.format_path(t),
00053 self._name, fmt_str)
00054 return result[:-1]
00055
00056 @property
00057 def formatter(self):
00058 '''Get the port's formatter function.'''
00059 return self._formatter
00060
00061 @property
00062 def input(self):
00063 '''If the port is an input port or not.'''
00064 return self._input
00065
00066 @property
00067 def name(self):
00068 '''The name of the port.'''
00069 return self._name
00070
00071 @property
00072 def output(self):
00073 '''If the port is an output port or not.'''
00074 return not self._input
00075
00076 @property
00077 def raw(self):
00078 '''The raw port specifications that created this PortSpec.'''
00079 return self._raw_specs
00080
00081 @property
00082 def targets(self):
00083 '''The target ports of this port, as [(path, port_name), ...].'''
00084 return self._targets
00085
00086 @property
00087 def type(self):
00088 '''The port's data type constructor function.'''
00089 return self._type
00090
00091 @property
00092 def type_name(self):
00093 '''The port's data type name.'''
00094 return self._type_name
00095
00096 def add_target(self, target, raw=''):
00097 '''Add an additional target for this port.'''
00098 self._targets.append(target)
00099 self._raw_specs.append(raw)
00100
00101
00102
00103
00104
00105 def make_port_specs(ports, modmgr, tree):
00106 '''Create a list of PortSpec objects matching the ports given.
00107
00108 The ports are searched for in the given RTCTree, and PortSpec objects are
00109 created matching them. The component holding each port is found, then the
00110 port object matching the given port name is found. A PortSpec is given
00111 matching its data type and with the reverse direction. If the target port
00112 is an InPort, a PortSpec for an OutPort will be created, and vice versa.
00113
00114 @param ports The paths to the target ports. Each must be a tuple of
00115 (path, port, name, formatter) where path is a list of path
00116 components in the format used by rtctree.
00117 @param modmgr The ModuleMgr object to use to evaluate the format
00118 expression.
00119 @param tree An RTCTree to search for the ports in.
00120
00121 '''
00122 result = {}
00123 index = 0
00124 for (rtc, port, name, form, raw) in ports:
00125 port_obj = comp_mgmt.find_port(rtc, port, tree)
00126 if port_obj.porttype == 'DataInPort':
00127 input = False
00128 elif port_obj.porttype == 'DataOutPort':
00129 input = True
00130 else:
00131 raise rts_exceptions.BadPortTypeError(rtc, port)
00132 if name is None:
00133 if input:
00134 name = 'input{0}'.format(index)
00135 else:
00136 name = 'output{0}'.format(index)
00137 index += 1
00138 data_type = port_obj.properties['dataport.data_type']
00139
00140 if data_type.startswith('IDL:'):
00141 data_type = data_type[4:]
00142 colon = data_type.rfind(':')
00143 if colon != -1:
00144 data_type = data_type[:colon]
00145 port_cons = modmgr.find_class(data_type)
00146 if form:
00147
00148 formatter = fmt.import_formatter(form, modmgr)
00149 else:
00150 formatter = None
00151 if name in result:
00152
00153 if (input != result[name].input or
00154 port_cons != result[name].type or
00155 formatter != result[name].formatter):
00156 raise rts_exceptions.SameNameDiffSpecError(raw)
00157 result[name].add_target((rtc, port), raw=raw)
00158 else:
00159 result[name] = (PortSpec(name, port_cons, (rtc, port), input=input,
00160 formatter=formatter,
00161 type_name=port_obj.properties['dataport.data_type'], raw=raw))
00162 return result.values()
00163
00164
00165 def parse_targets(targets):
00166 '''Parse target ports, as specified on the command line.
00167
00168 Parses target ports specified onto the command line into a tuple of
00169 (path, port, name, formatter, target), where path is in the rtctree
00170 format.
00171
00172 @param targets A list of target ports, as strings. Each string should
00173 be in the format "path:port.name#formatter", e.g.
00174 "/localhost/blurg.host_cxt/comp0.rtc:input.stuff#print_stuff".
00175 The name component is optional; if it is not present,
00176 neither should the '.' character be. The formatter
00177 component is optional; if it is not present, neither
00178 should the '#' character be. A name is not required
00179 to use a formatter.
00180
00181 '''
00182 regex = re.compile(r'^(?P<path>[:\-\w/.\(\)]+?)(?:\.(?P<name>\w+))?(?:#(?P<form>[\w.]+))?$')
00183 result = []
00184 for t in targets:
00185 m = regex.match(t)
00186 if not m:
00187 raise rts_exceptions.BadPortSpecError(t)
00188 raw_path, name, formatter = m.groups()
00189 path, port = rtctree.path.parse_path(raw_path)
00190 if not port or not path[-1]:
00191 raise rts_exceptions.BadPortSpecError(t)
00192 result.append((path, port, name, formatter, t))
00193 return result
00194
00195
00196 def require_all_input(port_specs):
00197 '''Checks that all ports in the specification are inputs.
00198
00199 Raises a @ref PortNotInputError exception if any ports are output.
00200
00201 @param port_specs A list of @ref PortSpec objects.
00202
00203 '''
00204 for p in port_specs:
00205 if not p.input:
00206 raise rts_exceptions.PortNotInputError(p.name)
00207
00208
00209 def require_all_output(port_specs):
00210 '''Checks that all ports in the specification are outputs.
00211
00212 Raises a @ref PortNotOutputError exception if any ports are output.
00213
00214 @param port_specs A list of @ref PortSpec objects.
00215
00216 '''
00217 for p in port_specs:
00218 if not p.output:
00219 raise rts_exceptions.PortNotOutputError(p.name)
00220