00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 PKG = 'life_test'
00038 import roslib
00039 roslib.load_manifest(PKG)
00040
00041 import rospy
00042
00043 from writing_core import *
00044
00045
00046 class LifeTest(object):
00047 """
00048 Holds parameters, info for each life test
00049 """
00050 def __init__(self, short = '', testid = '', name = '', desc = '', serial = '',
00051 duration = 0, launch_script = '', test_type = '', power = False, params = None):
00052 """
00053 Use **kwargs in constructor. Preferred option is to initialize from XML
00054 """
00055 self._short_serial = serial
00056 self._id = testid
00057 self._name = name
00058 self._short = short
00059 self._duration = duration
00060 self._desc = desc
00061 self._launch_script = launch_script
00062 self._test_type = test_type
00063 self._power = power
00064
00065 self._params = params if params else []
00066
00067 self._debug_ok = False
00068
00069 self._has_init = self._short_serial != '' and self._id != '' and self._name != '' \
00070 and self._launch_script != ''
00071
00072
00073 def init_xml(self, xml):
00074 """
00075 Initialize LifeTest from XML value.
00076
00077 Required tags:
00078 serial - Short value only
00079 name - Full name of test
00080 id - Test ID
00081 desc - Description
00082 script - Path to launch script
00083 type - Ex: 'Burn In'
00084 power - Needs power or not (bool)
00085
00086 Optional:
00087 debug - "true" if can run outside debug mode
00088 duration - Default: 0
00089
00090 TestParam's are initialized using nested XML nodes
00091 @raise Exception : If parameters are duplicated, or required attributes don't exist
00092 @return bool : True if init OK
00093 """
00094 self._short_serial = xml.attributes['serial'].value
00095 self._name = xml.attributes['name'].value
00096 self._id = xml.attributes['id'].value
00097 self._desc = xml.attributes['desc'].value
00098 self._launch_script = xml.attributes['script'].value
00099 self._test_type = xml.attributes['type'].value
00100 self._short = xml.attributes['short'].value
00101 self._power = xml.attributes['power'].value != 'false'
00102
00103 self._debug_ok = xml.attributes.has_key('debug') and \
00104 xml.attributes['debug'].value.lower() == "true"
00105
00106 if xml.attributes.has_key('duration'):
00107 self._duration = int(xml.attributes['duration'].value)
00108
00109 params_xml = xml.getElementsByTagName('param')
00110 for param_xml in params_xml:
00111 my_param = TestParam()
00112 my_param.init_xml(param_xml)
00113
00114 names = [ p.name for p in self._params ]
00115 if my_param.name in names:
00116 raise Exception("Param %s already exists in param list! XML: %s" % (my_param.name, xml.toprettyxml()))
00117
00118 self._params.append(my_param)
00119
00120 self._has_init = True
00121 return True
00122
00123 @property
00124 def debug_ok(self): return self._debug_ok
00125
00126 @property
00127 def need_power(self): return self._power
00128
00129 @property
00130 def short(self):
00131 return self._short
00132
00133 @property
00134 def desc(self):
00135 """Get description of test"""
00136 return self._desc
00137
00138 @property
00139 def params(self):
00140 """Get the parameters list. Read-only"""
00141 return self._params
00142
00143 @property
00144 def duration(self): return self._duration
00145
00146 @property
00147 def name(self): return self._name
00148
00149 @property
00150 def id(self): return self._id
00151
00152 @property
00153 def type(self): return self._test_type
00154
00155 @property
00156 def needs_power(self):
00157 return self.need_power
00158
00159 @property
00160 def launch_file(self):
00161 return self._launch_script
00162
00163 def set_params(self, namespace):
00164 """
00165 Sets parameters in given namespace
00166 """
00167 for param in self._params:
00168 param.set_namespace(namespace)
00169
00170
00171 def get_title(self, serial):
00172 """
00173 Return a human readable title of the test/item. Used as tab name
00174 """
00175 if len(serial) == 12:
00176 return "%s %s" % (self._short,
00177 serial[len(serial) - 3:
00178 len(serial)])
00179
00180 return self._short
00181
00182
00183 def validate(self):
00184 """
00185 Called during unit testing only. Checks all files exist, are valid
00186 @return bool : True if OK
00187 """
00188 if not self._has_init:
00189 return False
00190
00191 import os, sys
00192
00193 full_path = os.path.join(roslib.packages.get_pkg_dir(PKG), self._launch_script)
00194
00195 if not os.path.exists(full_path):
00196 print >> sys.stderr, "Test %s, path %s doesn't exist" % (self._name, full_path)
00197 return False
00198 if not full_path.endswith('.launch'):
00199 print >> sys.stderr, "Test %s, path %s is not a launch file" % (self._name, full_path)
00200 return False
00201
00202 return True
00203
00204 def make_param_table(self):
00205 """
00206 Writes parameters to HTML table form for logging
00207 @return str : Table as a string
00208 """
00209 if len(self._params) == 0:
00210 return '<p>No test parameters defined.</p>\n'
00211
00212 html = '<table border="1" cellpadding="2" cellspacing="0">\n'
00213 html += write_table_row(['Name', 'Value', 'Key', 'Description'], True)
00214 for param in self._params:
00215 html += write_table_row([param._name, param._value, param._param_name, param._desc])
00216 html += '</table>\n'
00217
00218 return html
00219
00220
00221
00222
00223
00224
00225 class TestParam(object):
00226 def __init__(self):
00227 self._value = ''
00228 self._desc = ''
00229
00230 self._cumulative = ''
00231 self._param_name = ''
00232 self._name = ''
00233 self._namespace = ''
00234
00235 def init_xml(self, param_xml):
00236 """
00237 Initialize from XML
00238
00239 Required elements:
00240 name - Name of param
00241 param_name - ROS name of param
00242 desc - Description
00243 value - Value of param
00244 rate = "true" if parameters is cumulative, or a rate
00245
00246 @raise Exception : If required attribs aren't present
00247 @return bool : True if OK
00248 """
00249 self._name = param_xml.attributes['name'].value
00250 self._param_name = param_xml.attributes['param_name'].value
00251 self._desc = param_xml.attributes['desc'].value
00252 self._value = param_xml.attributes['val'].value
00253 self._cumulative = param_xml.attributes['rate'].value == 'true'
00254
00255 return True
00256
00257 def set_namespace(self, ns):
00258 """
00259 Set parameter's value in appropriate namespace
00260 """
00261 self._namespace = ns
00262 rospy.set_param('/' + self._namespace + '/' + self._param_name, self._value)
00263
00264 @property
00265 def value(self):
00266 try:
00267 val = float(self._value)
00268 return val
00269 except:
00270 return str(self._value)
00271
00272 @property
00273 def name(self): return self._name
00274
00275 @property
00276 def rate(self):
00277 return self._cumulative
00278