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 Implementation of the logging command.
00018
00019 '''
00020
00021
00022 import optparse
00023 import os
00024 import os.path
00025 import rtctree.tree
00026 import rtctree.utils
00027 import sys
00028 import threading
00029 import time
00030 import traceback
00031 import OpenRTM_aist
00032 import RTC
00033
00034 import comp_mgmt
00035 import modmgr
00036 import path
00037 import port_types
00038 import rtlog_comps
00039 import rts_exceptions
00040 import rtshell
00041 import simpkl_log
00042 import text_log
00043
00044
00045 def record_log(raw_paths, options, tree=None):
00046 event = threading.Event()
00047
00048 if options.end is not None and options.end < 0:
00049 raise rts_exceptions.BadEndPointError
00050 if options.end is None and options.index:
00051 print >>sys.stderr, '{0}: WARNING: --index has no effect without '\
00052 '--end'.format(os.path.basename(sys.argv[0]))
00053
00054 mm = modmgr.ModuleMgr(verbose=options.verbose, paths=options.paths)
00055 mm.load_mods_and_poas(options.modules)
00056 if options.verbose:
00057 print >>sys.stderr, \
00058 'Pre-loaded modules: {0}'.format(mm.loaded_mod_names)
00059
00060 if options.timeout is not None:
00061 print >>sys.stderr, 'Recording for {0}s.'.format(options.timeout)
00062 else:
00063 if options.end is not None:
00064 if options.index:
00065 print >>sys.stderr, 'Recording {0} entries.'.format(
00066 int(options.end))
00067 else:
00068 end_str = time.strftime('%Y-%m-%d %H:%M:%S',
00069 time.localtime(options.end))
00070 print >>sys.stderr, 'Recording until {0} ({1}).'.format(
00071 end_str, options.end)
00072
00073 if options.logger == 'simpkl':
00074 l_type = simpkl_log.SimplePickleLog
00075 elif options.logger == 'text':
00076 l_type = text_log.TextLog
00077 else:
00078 raise rts_exceptions.BadLogTypeError(options.logger)
00079
00080 sources = port_types.parse_targets(raw_paths)
00081 if not tree:
00082 paths = [s[0] for s in sources]
00083 tree = rtctree.tree.RTCTree(paths=paths, filter=paths)
00084 port_specs = port_types.make_port_specs(sources, mm, tree)
00085 port_types.require_all_input(port_specs)
00086 if options.verbose:
00087 print >>sys.stderr, \
00088 'Port specifications: {0}'.format([str(p) for p in port_specs])
00089
00090 if options.end is None:
00091 end = -1
00092 else:
00093 end = options.end
00094 comp_name, mgr = comp_mgmt.make_comp('rtlog_recorder', tree,
00095 rtlog_comps.Recorder, port_specs, event=event,
00096 logger_type=l_type, filename=options.filename,
00097 lims_are_ind=options.index, end=end,
00098 verbose=options.verbose, rate=options.exec_rate)
00099 if options.verbose:
00100 print >>sys.stderr, 'Created component {0}'.format(comp_name)
00101 try:
00102 comp = comp_mgmt.find_comp_in_mgr(comp_name, mgr)
00103 comp_mgmt.connect(comp, port_specs, tree)
00104 comp_mgmt.activate(comp)
00105 except Exception, e:
00106
00107 raise e
00108 try:
00109 if options.timeout is not None:
00110 event.wait(options.timeout)
00111 comp_mgmt.disconnect(comp)
00112 comp_mgmt.deactivate(comp)
00113 elif options.end is not None:
00114 event.wait()
00115 comp_mgmt.disconnect(comp)
00116 comp_mgmt.deactivate(comp)
00117 else:
00118 while True:
00119 raw_input()
00120
00121
00122 except KeyboardInterrupt:
00123 pass
00124 except EOFError:
00125 pass
00126 tree.give_away_orb()
00127 del tree
00128 comp_mgmt.shutdown(mgr)
00129
00130
00131 def play_log(raw_paths, options, tree=None):
00132 event = threading.Event()
00133
00134 if not options.filename:
00135 raise rts_exceptions.NoLogFileNameError
00136 if options.start is not None and options.start < 0:
00137 raise rts_exceptions.BadStartPointError
00138 if options.end is not None and options.end < 0:
00139 raise rts_exceptions.BadEndPointError
00140 if options.end is None and options.start is None and options.index:
00141 print >>sys.stderr, '{0}: WARNING: --index has no effect without '\
00142 '--start or --end'.format(os.path.basename(sys.argv[0]))
00143
00144 mm = modmgr.ModuleMgr(verbose=options.verbose, paths=options.paths)
00145 mm.load_mods_and_poas(options.modules)
00146 if options.verbose:
00147 print >>sys.stderr, \
00148 'Pre-loaded modules: {0}'.format(mm.loaded_mod_names)
00149
00150 if options.timeout is not None:
00151 print >>sys.stderr, 'Playing for {0}s.'.format(options.timeout)
00152 else:
00153 if options.end is not None:
00154 if options.start is not None:
00155 if options.index:
00156 print >>sys.stderr, 'Playing from entry {0} to entry '\
00157 '{1}.'.format(int(options.start), int(options.end))
00158 else:
00159 start_str = time.strftime('%Y-%m-%d %H:%M:%S',
00160 time.localtime(options.start))
00161 end_str = time.strftime('%Y-%m-%d %H:%M:%S',
00162 time.localtime(options.end))
00163 print >>sys.stderr, 'Playing from {0} ({1}) until {2} '\
00164 '({3}).'.format(start_str, options.start, end_str,
00165 options.end)
00166 else:
00167 if options.index:
00168 print >>sys.stderr, 'Playing {0} entries.'.format(
00169 int(options.end))
00170 else:
00171 end_str = time.strftime('%Y-%m-%d %H:%M:%S',
00172 time.localtime(options.end))
00173 print >>sys.stderr, 'Playing until {0} ({1}).'.format(
00174 end_str, options.end)
00175 elif options.start is not None:
00176 if options.index:
00177 print >>sys.stderr, 'Playing from entry {0}.'.format(
00178 int(options.start))
00179 else:
00180 start_str = time.strftime('%Y-%m-%d %H:%M:%S',
00181 time.localtime(options.start))
00182 print >>sys.stderr, 'Playing from {0} ({1}).'.format(start_str,
00183 options.start)
00184
00185 if options.logger == 'simpkl':
00186 l_type = simpkl_log.SimplePickleLog
00187 elif options.logger == 'text':
00188 raise rts_exceptions.UnsupportedLogTypeError('text', 'playback')
00189 else:
00190 raise rts_exceptions.BadLogTypeError(options.logger)
00191
00192 targets = port_types.parse_targets(raw_paths)
00193 if not tree:
00194 paths = [t[0] for t in targets]
00195 tree = rtctree.tree.RTCTree(paths=paths, filter=paths)
00196 port_specs = port_types.make_port_specs(targets, mm, tree)
00197 if options.verbose:
00198 print >>sys.stderr, \
00199 'Port specifications: {0}'.format([str(p) for p in port_specs])
00200 port_types.require_all_output(port_specs)
00201
00202 if options.start is None:
00203 start = 0
00204 else:
00205 start = options.start
00206 if options.end is None:
00207 end = -1
00208 else:
00209 end = options.end
00210 comp_name, mgr = comp_mgmt.make_comp('rtlog_player', tree,
00211 rtlog_comps.Player, port_specs, event=event, logger_type=l_type,
00212 filename=options.filename, lims_are_ind=options.index, start=start,
00213 end=end, scale_rate=options.rate, abs_times=options.abs_times,
00214 ignore_times=options.ig_times, verbose=options.verbose,
00215 rate=options.exec_rate)
00216 if options.verbose:
00217 print >>sys.stderr, 'Created component {0}'.format(comp_name)
00218 comp = comp_mgmt.find_comp_in_mgr(comp_name, mgr)
00219 comp_mgmt.connect(comp, port_specs, tree)
00220 comp_mgmt.activate(comp)
00221 try:
00222 if options.timeout is not None:
00223 event.wait(options.timeout)
00224 comp_mgmt.disconnect(comp)
00225 try:
00226 comp_mgmt.deactivate(comp)
00227 except rts_exceptions.DeactivateError:
00228
00229
00230 pass
00231
00232 else:
00233 event.wait()
00234 comp_mgmt.disconnect(comp)
00235 try:
00236 comp_mgmt.deactivate(comp)
00237 except rts_exceptions.DeactivateError:
00238
00239
00240 pass
00241
00242
00243
00244
00245
00246 except KeyboardInterrupt:
00247 pass
00248 except EOFError:
00249 pass
00250 tree.give_away_orb()
00251 del tree
00252 comp_mgmt.shutdown(mgr)
00253
00254
00255 def display_info(options):
00256 if not options.filename:
00257 raise rts_exceptions.NoLogFileNameError
00258
00259 if options.logger == 'simpkl':
00260 l_type = simpkl_log.SimplePickleLog
00261 elif options.logger == 'text':
00262 raise rts_exceptions.UnsupportedLogTypeError('text', 'inspection')
00263 else:
00264 raise rts_exceptions.BadLogTypeError(options.logger)
00265
00266 mm = modmgr.ModuleMgr(verbose=options.verbose, paths=options.paths)
00267 mm.load_mods_and_poas(options.modules)
00268 if options.verbose:
00269 print >>sys.stderr, \
00270 'Pre-loaded modules: {0}'.format(mm.loaded_mod_names)
00271
00272 statinfo = os.stat(options.filename)
00273 size = statinfo.st_size
00274 if size > 1024 * 1024 * 1024:
00275 size_str = '{0:.2f}GiB ({1}B)'.format(size / (1024.0 * 1024 * 1024), size)
00276 elif size > 1024 * 1024:
00277 size_str = '{0:.2f}MiB ({1}B)'.format(size / (1024.0 * 1024), size)
00278 elif size > 1024:
00279 size_str = '{0:.2f}KiB ({1}B)'.format(size / 1024.0, size)
00280 else:
00281 size_str = '{0}B'.format(size)
00282 log = l_type(filename=options.filename, mode='r', verbose=options.verbose)
00283
00284 start_time, port_specs = log.metadata
00285 start_time_str = time.strftime('%Y-%m-%d %H:%M:%S',
00286 time.localtime(start_time))
00287 first_ind, first_time = log.start
00288 first_time_str = time.strftime('%Y-%m-%d %H:%M:%S',
00289 time.localtime(first_time.float))
00290 end_ind, end_time = log.end
00291 end_time_str = time.strftime('%Y-%m-%d %H:%M:%S',
00292 time.localtime(end_time.float))
00293
00294 print 'Name: {0}'.format(options.filename)
00295 print 'Size: ' + size_str
00296 print 'Start time: {0} ({1})'.format(start_time_str, start_time)
00297 print 'First entry time: {0} ({1})'.format(first_time_str, first_time)
00298 print 'End time: {0} ({1})'.format(end_time_str, end_time)
00299 print 'Number of entries: {0}'.format(end_ind + 1)
00300 for ii, p in enumerate(port_specs):
00301 print 'Channel {0}'.format(ii + 1)
00302 print ' Name: {0}'.format(p.name)
00303 print ' Data type: {0} ({1})'.format(p.type_name, p.type)
00304 print ' Sources:'
00305 for r in p.raw:
00306 print ' {0}'.format(r)
00307
00308
00309 def main(argv=None, tree=None):
00310 usage = '''Usage: %prog [options] <path1>:<port1> [<path2>:<port2>...]
00311 Record data from output ports, or replay data into input ports.'''
00312 version = rtshell.RTSH_VERSION
00313 parser = optparse.OptionParser(usage=usage, version=version)
00314 parser.add_option('-a', '--absolute-times', dest='abs_times',
00315 action='store_true', default=False,
00316 help='Times from the logged data are sent as recorded during '
00317 'replay, rather than adjusted to the current timeframe. '
00318 '[Default: %default]')
00319 parser.add_option('-d', '--display-info', dest='display_info',
00320 action='store_true', default=False, help='Display the log '
00321 'information and exit.')
00322 parser.add_option('-e', '--end', dest='end', action='store', type='float',
00323 default=None,
00324 help='Time or entry index to stop recording or playback. Must be '
00325 'within the bounds of the log. Specify -1 to record forever or '
00326 'replay to the end of the log. Use --index to specify that this '
00327 'value is an index. [Default: %default]')
00328 parser.add_option('-f', '--filename', dest='filename', action='store',
00329 type='string', default='', help='File name of the log file to '
00330 'record to/playback from. If not specified for recording, a '
00331 'default will be created based on the current time. Must be '
00332 'specified for playback.')
00333 parser.add_option('--path', dest='paths', action='append', type='string',
00334 default=[], help='Extra module search paths to add to the '
00335 'PYTHONPATH.')
00336 parser.add_option('-i', '--index', dest='index', action='store_true',
00337 default=False, help='Interpret the start and end values as entry '
00338 'indices. [Default: %default]')
00339 parser.add_option('-l', '--logger', dest='logger', action='store',
00340 type='string', default='simpkl', help='The type of logger to '
00341 'use. The default is the SimplePickle logger. Alternatively, '
00342 'the text logger (specify using "text") may be used. The text '
00343 'logger does not support playback.')
00344 parser.add_option('-m', '--mod', dest='modules', action='append',
00345 type='string', default=[],
00346 help='Extra modules to import. If automatic module loading '
00347 'struggles with your data types, try listing the modules here. '
00348 'The module and its __POA partner will be imported.')
00349 parser.add_option('-n', '--ignore-times', dest='ig_times',
00350 action='store_true', default=False, help='Ignore the log '
00351 'timestamps and play back a fixed number of entries per '
00352 'execution. Use --rate to change the number played back per '
00353 'execution. The value of --rate will be treated as an integer '
00354 'in this case.')
00355 parser.add_option('-p', '--play', dest='play', action='store_true',
00356 default=False, help='Replay mode. [Default: %default]')
00357 parser.add_option('-r', '--rate', dest='rate', action='store',
00358 type='float', default=1.0,
00359 help='Scale the playback speed of the log. [Default: %default]')
00360 parser.add_option('-s', '--start', dest='start', action='store',
00361 type='float', default=None,
00362 help='Time or entry index to start playback from. Must be within '
00363 'the bounds of the log. Use --index to specify that this value '
00364 'is an index. [Default: %default]')
00365 parser.add_option('-t', '--timeout', dest='timeout', action='store',
00366 type='float', default=None, help='Record/replay data for this '
00367 'many seconds. This option overrides --start/--end.')
00368 parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
00369 default=False,
00370 help='Output verbose information. [Default: %default]')
00371 parser.add_option('-x', '--exec-rate', dest='exec_rate', action='store',
00372 type='float', default=100.0,
00373 help='Specify the rate in Hertz at which to run the component. '
00374 '[Default: %default]')
00375
00376 if argv:
00377 sys.argv = [sys.argv[0]] + argv
00378 try:
00379 options, args = parser.parse_args()
00380 except optparse.OptionError, e:
00381 print >>sys.stderr, 'OptionError:', e
00382 return 1
00383
00384 if len(args) < 1 and not options.display_info:
00385 print >>sys.stderr, usage
00386 return 1
00387
00388 try:
00389 if options.display_info:
00390 display_info(options)
00391 elif options.play:
00392 play_log([path.cmd_path_to_full_path(p) for p in args],
00393 options, tree)
00394 else:
00395 record_log([path.cmd_path_to_full_path(p) for p in args],
00396 options, tree)
00397 except Exception, e:
00398 if options.verbose:
00399 traceback.print_exc()
00400 print >>sys.stderr, '{0}: {1}'.format(os.path.basename(sys.argv[0]), e)
00401 return 1
00402 return 0
00403