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
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 if __name__ == "__main__":
00055
00056
00057 try:
00058 from .. import utils
00059
00060
00061 except:
00062
00063
00064 print ("ERROR: clearpath.cli is a module and must be run "\
00065 "by:\n python -m clearpath.cli")
00066
00067
00068 import sys
00069 sys.exit(1)
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 """Horizon Basic Command-Line Controller
00166
00167 Copyright © 2010 Clearpath Robotics, Inc.
00168 All rights reserved
00169
00170 Created: 14/01/10
00171 Author: Ryan Gariepy & Malcolm Robert
00172 Version: 1.0
00173 """
00174
00175
00176 from .. import utils
00177 from . import Horizon
00178 from . import logger as horizon_logger
00179
00180 from . import messages
00181 from . import payloads
00182 from . import protocol
00183 from . import transports
00184
00185
00186 import cmd
00187 import datetime
00188 import inspect
00189 import logging
00190 import optparse
00191 import os
00192 import re
00193 import sys
00194 import threading
00195 import time
00196 import readline
00197
00198
00199 try:
00200 import serial
00201 except ImportError:
00202 pass
00203
00204
00205
00206
00207 __version__ = "1.0"
00208 """Module Version"""
00209
00210 __revision__ = "$Revision: 800 $"
00211 """SVN Code Revision"""
00212
00213
00214
00215
00216 logger = logging.getLogger('clearpath.horizon.demo')
00217 """Horizon Demo Module Log"""
00218 logger.setLevel(logging.NOTSET)
00219 logger.addHandler(utils.NullLoggingHandler())
00220 logger.propagate = False
00221 logger.debug("Loading clearpath.horizon.demo ...")
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 class HorizonDemo(cmd.Cmd):
00240 """Horizon Command-Line Controller"""
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 def __init__(self,port,horizon,output=''):
00254 """Create A Horizon Command-Line Controller"""
00255 logger.debug("%s: Instance creation started..." % \
00256 self.__class__.__name__)
00257
00258 cmd.Cmd.__init__(self)
00259
00260
00261
00262 self._commands = []
00263
00264
00265 self._cmd_lock = threading.RLock()
00266
00267 self._horizon = horizon
00268
00269 self._output = None
00270
00271 self._repeater = threading.Thread(target = self._repeat)
00272
00273 self._repeating = False
00274
00275
00276 self.intro = "\n------------------------------\n" \
00277 "-- Horizon --\n" \
00278 "-- Clearpath Robotics, Inc. --\n" \
00279 "------------------------------\n\n" \
00280 "Basic Horizon Interactive Command-Line Controller "\
00281 "Type 'help' to get the list of available commands.\n\n"\
00282 "%s\n" % self._about()
00283 self.doc_leader = \
00284 "\nBasic Horizon Interactive Command-Line Controller \n"\
00285 "These shell commands are defined internally. "\
00286 "Type 'help' to see this list.\n"\
00287 "Type 'help <name>' to find out how to use the command 'name'.\n"\
00288 "Use 'horizon_demo --doc' to find out more about Horizon in "\
00289 "general.\n"
00290 self.prompt = 'horizon:' + port + '$ '
00291
00292
00293 for i in Horizon.__dict__:
00294
00295
00296 if i[0] != '_':
00297
00298
00299
00300
00301 def tmp(self,line,method=i):
00302 self._parse_arguments(method=getattr(self._horizon,method),
00303 arguments=line)
00304
00305 def tmp_help(self,method=i):
00306 self._print_help(method)
00307
00308
00309
00310 tmp.__doc__ = getattr(self._horizon,i).__doc__
00311
00312
00313 setattr(HorizonDemo, "do_"+i, tmp)
00314 setattr(HorizonDemo, "help_"+i, tmp_help)
00315
00316
00317 if output == '' or output == '/dev/null' or output == None:
00318 setattr(HorizonDemo, "do_get_waiting", self._waiting)
00319 setattr(HorizonDemo, "complete_get_waiting", self._waiting_complete)
00320
00321
00322 else:
00323 self._output = logging.getLogger("HorizonDemo")
00324 self._output.setLevel(logging.DEBUG)
00325 logger_handler = logging.FileHandler(filename=output)
00326 logger_handler.setFormatter(logging.Formatter("%(message)s"))
00327 self._output.addHandler(logger_handler)
00328
00329
00330 self._repeater.setDaemon(True)
00331
00332 logger.debug("%s: ...instance creation complete." % \
00333 self.__class__.__name__)
00334
00335
00336
00337
00338
00339
00340
00341
00342 def __del__(self):
00343 """Destroy a Horizon Demo."""
00344 logger.debug("%s: Instance destruction started..." % \
00345 self.__class__.__name__)
00346
00347
00348 self._repeating = False
00349
00350 logger.debug("%s: ...instance destruction complete." %
00351 self.__class__.__name__)
00352
00353
00354
00355
00356
00357
00358
00359 def _about(self):
00360 """Get Horizon About String"""
00361
00362 result = ""
00363
00364
00365 try:
00366
00367 result += '-- Horizon --\n'\
00368 'Transport: %s\n'\
00369 'Device: %s\n'\
00370 'Version: %d.%d\n' % \
00371 (self._horizon._protocol._transport.__class__.__name__,
00372 str(self._horizon._protocol._transport),
00373 self._horizon.version[0],self._horizon.version[1])
00374
00375
00376 name = self._horizon.request_platform_name()
00377 result += '-- Platform --\n'\
00378 'Name: %s\n' % (name.name)
00379
00380
00381 info = self._horizon.request_platform_info()
00382 result += 'Model: %s\n'\
00383 'Revision: %d\n'\
00384 'Serial Number: %010d\n' % (info.model, info.revision, info.serial)
00385
00386
00387 firm = self._horizon.request_firmware_info()
00388 result += '-- Firmware --\n'\
00389 'Horizon: %d.%d\n'\
00390 'Version: %d.%d\n'\
00391 'Last Updated: %s\n' % (firm.version[0], firm.version[1],
00392 firm.firmware[0], firm.firmware[1],
00393 firm.written.strftime("%I:%M %p - %B %d, %Y"))
00394
00395
00396 syst = self._horizon.request_system_status()
00397 sec = syst.uptime
00398 mil = sec % 1000
00399 sec = (sec - mil) / 1000
00400 min = sec
00401 sec = min % 60
00402 min = (min - sec) / 60
00403 hou = min
00404 min = hou % 60
00405 hou = (hou - min) / 60
00406 day = hou
00407 hou = day % 24
00408 day = (day - hou) / 24
00409 result += '-- Status --\n'\
00410 'Uptime: %02ddays %02dh %02dm %02ds %03dms\n'\
00411 % (day, hou, min, sec, mil)
00412
00413
00414 powe = self._horizon.request_power_status()
00415 result += '-- Status --\n'
00416 result += 'Power: %02.2f%%\n' % ((sum(powe.charges,0.0)/
00417 len(powe.charges)))
00418
00419
00420 safe = self._horizon.request_safety_status()
00421 emer = ''
00422 if safe.has_emergency_stop():
00423 emer = 'EMERGENCY STOP'
00424 elif safe.flags & 0x0002 > 0:
00425 emer = 'PAUSED'
00426 result += 'Mode: %s\n' % (emer)
00427
00428
00429 except NotImplementedError as ex:
00430 logger.error(str(ex))
00431 result = "ERROR: Failed to obtain device info!"
00432 except utils.SubscriptionError as ex:
00433 logger.error(str(ex))
00434 result = "ERROR: Failed to obtain device info!"
00435 except utils.TimeoutError as ex:
00436 logger.error(str(ex))
00437 result = "ERROR: Failed to obtain device info!"
00438 except utils.TransportError as ex:
00439 logger.error(str(ex))
00440 result = "ERROR: Failed to obtain device info!"
00441 except ValueError as ex:
00442 logger.error(str(ex))
00443 result = "ERROR: Failed to obtain device info!"
00444
00445
00446 return result[:-1]
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 def _extract_arguments(self, arguments):
00458 """Extract arguments from a Line."""
00459
00460
00461 quote = '(?:(?P<quo>[\"\'])(.+?)(?P=quo))'
00462 escapes = '(?:(?:\\\\\\s)|(?:\\\\a)|(?:\\\\b)|(?:\\\\f)|(?:\\\\n)|' \
00463 '(?:\\\\r)|(?:\\\\t)|(?:\\\\v)|(?:\\\\\\\\))'
00464 nonwhite = '(?:[^\\t\\n\\r\\f\\v\\\\\\ ])'
00465 token = '(?:(?:'+escapes+'|'+nonwhite+')+)'
00466 block = '('+quote+'|'+token+')'
00467 line = '^'+token+'(?:\\s+'+token+')*$'
00468 parser = re.compile(line)
00469 matcher = re.compile(block)
00470 replacer = re.compile('\\\\([^\\\\])')
00471
00472
00473 arguments = arguments.strip()
00474 match = parser.match(arguments)
00475 params = []
00476 if match != None:
00477 match = matcher.findall(arguments)
00478 for sub in match:
00479 rsub = sub[0]
00480
00481
00482 if sub[1] != '':
00483 rsub = sub[2]
00484
00485
00486 if sub[1] != "'":
00487 rsub = rsub.replace('\\a','\a')
00488 rsub = rsub.replace('\\b','\b')
00489 rsub = rsub.replace('\\f','\f')
00490 rsub = rsub.replace('\\n','\n')
00491 rsub = rsub.replace('\\r','\r')
00492 rsub = rsub.replace('\\t','\t')
00493 rsub = rsub.replace('\\v','\v')
00494 rsub = replacer.sub(r'\1',rsub)
00495 rsub = rsub.replace('\\\\','\\')
00496
00497
00498 params.append(rsub)
00499
00500
00501 return params
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 def _arguments_to_values(self, params, method):
00515 """Convert arguments to their proper types."""
00516
00517
00518 args = inspect.getargspec(method)
00519 if 'handler' in args[0]:
00520 args[0].remove('handler')
00521 if 'subscription' in args[0]:
00522 args[0].remove('subscription')
00523 values = {}
00524
00525
00526 yes = re.compile('^(?:(?:[yY][eE][sS])|(?:[tT][rR][uU][eE])|(?:1))$')
00527 no = re.compile('^(?:(?:[nN][oO])|(?:[fF][aA][lL][sS][eE])|(?:0))$')
00528
00529
00530 if (params == None and len(args[0]) > 1) or \
00531 (len(params) != len(args[0]) - 1 and (len(args[0]) == 1 or
00532 type(args[3][-2]) != dict)):
00533 print(("ERROR: %s invalid number of arguments" % method.__name__))
00534 return None
00535
00536
00537 for i,param in enumerate(params):
00538
00539
00540 if type(args[3][i]) == dict:
00541 values[args[0][i+1]] = {}
00542
00543
00544 for j in range(i,len(params)):
00545 tokens = params[j].split(':')
00546 if len(tokens) != 2:
00547 print(("ERROR: %s argument %d: must be key:value" % (
00548 method.__name__, (j+1))))
00549 return None
00550 key = None
00551 if type(list(args[3][i].keys())[0]) == str:
00552 key = tokens[0]
00553 elif type(list(args[3][i].keys())[0]) == float:
00554 try:
00555 key = float(tokens[0])
00556 except ValueError:
00557 print(("ERROR: %s argument %d: key must be a float"\
00558 % (method.__name__, (j+1))))
00559 return None
00560 elif sys.version_info[0] < 3 and \
00561 type(list(args[3][i].keys())[0]) == int:
00562 try:
00563 key = int(tokens[0])
00564 except ValueError:
00565 print(("ERROR: %s argument %d: key must be a long"\
00566 % (method.__name__,(j+1))))
00567 return None
00568 elif type(list(args[3][i].keys())[0]) == int:
00569 try:
00570 key = int(tokens[0])
00571 except ValueError:
00572 print(("ERROR: %s argument %d: key must be an int"\
00573 % (method.__name__,(j+1))))
00574 return None
00575 elif type(list(args[3][i].keys())[0]) == bool:
00576 if yes.match(tokens[0]):
00577 key = True
00578 elif no.match(tokens[0]):
00579 key = False
00580 else:
00581 print(("ERROR: %s argument %d: key must be a "\
00582 "boolean" % (method.__name__,(j+1))))
00583 return None
00584 print (key)
00585 if type(args[3][i][list(args[3][i].keys())[0]]) == str:
00586 values[args[0][i+1]][key] = tokens[1]
00587 elif type(args[3][i][list(args[3][i].keys())[0]]) == float:
00588 try:
00589 values[args[0][i+1]][key] = float(tokens[1])
00590 except ValueError:
00591 print(("ERROR: %s argument %d: key must be a float"\
00592 % (method.__name__, (j+1))))
00593 return None
00594 elif sys.version_info[0] < 3 and \
00595 type(args[3][i][list(args[3][i].keys())[0]]) == int:
00596 try:
00597 values[args[0][i+1]][key] = int(tokens[1])
00598 except ValueError:
00599 print(("ERROR: %s argument %d: key must be a long"\
00600 % (method.__name__,(j+1))))
00601 return None
00602 elif type(args[3][i][list(args[3][i].keys())[0]]) == int:
00603 try:
00604 values[args[0][i+1]][key] = int(tokens[1])
00605 except ValueError:
00606 print(("ERROR: %s argument %d: key must be an int"\
00607 % (method.__name__,(j+1))))
00608 return None
00609 elif type(args[3][i][list(args[3][i].keys())[0]]) == bool:
00610 if yes.match(tokens[1]):
00611 values[args[0][i+1]][key] = True
00612 elif no.match(tokens[1]):
00613 values[args[0][i+1]][key] = False
00614 else:
00615 print(("ERROR: %s argument %d: key must be a "\
00616 "boolean" % (method.__name__,(j+1))))
00617 return None
00618 print((values[args[0][i+1]]))
00619 break
00620
00621
00622 elif type(args[3][i]) == str:
00623 values[args[0][i+1]] = param
00624
00625
00626 elif type(args[3][i]) == float:
00627 try:
00628 values[args[0][i+1]] = float(param)
00629 except ValueError:
00630 print(("ERROR: %s argument %d: value must be a float" % (
00631 method.__name__, (i+1))))
00632 return None
00633
00634
00635 elif sys.version_info[0] < 3 and type(args[3][i]) == int:
00636 try:
00637 values[args[0][i+1]] = int(param)
00638 except ValueError:
00639 print(("ERROR: %s argument %d: value must be a long" % (
00640 method.__name__,(i+1))))
00641 return None
00642
00643
00644 elif type(args[3][i]) == int:
00645 try:
00646 values[args[0][i+1]] = int(param)
00647 except ValueError:
00648 print(("ERROR: %s argument %d: value must be an int" % (
00649 method.__name__,(i+1))))
00650 return None
00651
00652
00653 elif type(args[3][i]) == bool:
00654 if yes.match(param):
00655 values[args[0][i+1]] = True
00656 elif no.match(param):
00657 values[args[0][i+1]] = False
00658 else:
00659 print(("ERROR: %s argument %d: value must be a boolean" % (
00660 method.__name__,(i+1))))
00661 return None
00662
00663
00664 return values
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 def _parse_arguments(self,method,arguments):
00679 """Parse a Line of Arguments"""
00680
00681
00682 params = self._extract_arguments(arguments)
00683
00684
00685 values = self._arguments_to_values(params, method)
00686 if values == None: return
00687
00688
00689 try:
00690 result = method(**values)
00691 if result: print((result.print_format()))
00692 except NotImplementedError as ex:
00693 print(("ERROR: %s is not supported on the platform!" % \
00694 method.__name__))
00695 logger.debug(ex)
00696 except utils.TransportError as ex:
00697 print(("ERROR: Transport send for %s failed!" % \
00698 method.__name__))
00699 logger.debug(ex)
00700 except ValueError as ex:
00701 print(("ERROR: " + str(ex)))
00702 logger.debug(ex)
00703 except utils.TimeoutError as ex:
00704 print(("ERROR: Timeout occured waiting for %s completion!" % \
00705 method.__name__))
00706 logger.debug(ex)
00707
00708
00709
00710
00711 def _print_help(self, method):
00712 helpstr = 'usage: ' + method
00713 argspec = inspect.getargspec(getattr(self._horizon, method))
00714
00715
00716 for i in range(len(argspec.args)):
00717
00718 if argspec.args[i] in ['self', 'subscription', 'handler'] :
00719 continue
00720
00721 if i < (len(argspec.args) - len(argspec.defaults)) :
00722
00723 helpstr += ' <' + argspec.args[i] + '>'
00724 else:
00725
00726 argtype = str(type(argspec.defaults[i-len(argspec.args)]))
00727
00728 argtype = argtype[argtype.index('\'')+1:]
00729 argtype = argtype[:argtype.index('\'')]
00730 helpstr += ' <' + argtype + ' ' + argspec.args[i] + '>'
00731
00732 print(helpstr)
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 def _handler(self, payload):
00743 """Output Subscription Data"""
00744
00745
00746 sec = payload.timestamp
00747 mil = sec % 1000
00748 sec = (sec - mil) / 1000
00749 min = sec
00750 sec = min % 60
00751 min = (min - sec) / 60
00752 hou = min
00753 min = hou % 60
00754 hou = (hou - min) / 60
00755 day = hou
00756 hou = day % 24
00757 day = (day - hou) / 24
00758
00759 if payload.error != None:
00760 self._output.debug('-- %02ddays %02dh %02dm %02ds %03dms --\n%s' % (
00761 day, hou, min, sec, mil, str(payload.error)))
00762 else:
00763 self._output.debug('-- %02ddays %02dh %02dm %02ds %03dms --\n%s' % (
00764 day, hou, min, sec, mil, payload.print_format()))
00765
00766
00767
00768
00769
00770
00771
00772 def _repeat(self):
00773 """Command Repeater Loop"""
00774 logger.debug("%s: Entering repeat loop..." % self.__class__.__name__)
00775
00776
00777 while self._repeating:
00778
00779
00780 if len(self._commands) == 0:
00781 self._repeating = False
00782 self._repeater = threading.Thread(target = self._repeat)
00783 self._repeater.setDaemon(True)
00784 break
00785
00786
00787 timestamp = 0
00788 t = datetime.datetime.today()
00789 timestamp = t.microsecond/1000 + t.second*1000 + \
00790 t.minute*60*1000 + t.hour*60*60*1000 + t.day*24*60*60*1000
00791 while timestamp > 4294967295: timestamp -= 4294967295
00792 if sys.version_info[0] > 2:
00793 timestamp = int(timestamp)
00794 else:
00795 timestamp = int(timestamp)
00796
00797
00798 self._cmd_lock.acquire()
00799 try:
00800 for cmd in self._commands:
00801 diff = 0
00802 if timestamp > cmd[0]:
00803 diff = timestamp - cmd[0]
00804 else:
00805 diff = 4294967295 - cmd[0] + timestamp
00806 if diff % int(1000/cmd[1]) == 0:
00807
00808 try:
00809 cmd[2][0](**cmd[2][1])
00810 except Exception:
00811 pass
00812 finally:
00813 self._cmd_lock.release()
00814
00815
00816 time.sleep(0.001)
00817
00818 logger.debug("%s: ...repeat loop exited." % self.__class__.__name__)
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828 def _waiting(self, line):
00829 """syntax: get_waiting [<request>]\n""" \
00830 """-- Show any data received from a subscription on 'request'.\n""" \
00831 """ If request is not specified then list all data."""
00832
00833
00834 params = self._extract_arguments(line)
00835
00836
00837 if len(params) > 1:
00838 print ("ERROR: too many arguments!")
00839 return
00840
00841
00842 request = None
00843 if len(params) == 1:
00844 if not params[0] in self.completenames('request_'):
00845 print ("ERROR: Unsupported / Invalid command!")
00846 return
00847 method = None
00848 try:
00849 method = getattr(self._horizon, params[0])
00850 except AttributeError:
00851 print ("ERROR: Unsupported / Invalid command!")
00852 return
00853 args = inspect.getargspec(method)
00854 if not 'subscription' in args[0]:
00855 print(("ERROR: %s does not support subscriptions!" % params[1]))
00856 return
00857 request = params[0]
00858
00859
00860 data = []
00861 try:
00862 data = self._horizon.get_waiting_data(request=request)
00863 except Exception as ex:
00864 print(("Error: unexpected error encountered!\n%s" % str(ex)))
00865
00866
00867 if len(data) == 0:
00868 if request == None:
00869 print ("No data.")
00870 else:
00871 print(("No data for %s." % request))
00872 else:
00873 for payload in data:
00874 if isinstance(payload[1], payloads.Null):
00875 continue
00876
00877
00878 sec = payload[2]
00879 mil = sec % 1000
00880 sec = (sec - mil) / 1000
00881 min = sec
00882 sec = min % 60
00883 min = (min - sec) / 60
00884 hou = min
00885 min = hou % 60
00886 hou = (hou - min) / 60
00887 day = hou
00888 hou = day % 24
00889 day = (day - hou) / 24
00890
00891 print(('-- %02ddays %02dh %02dm %02ds %03dms --' % (
00892 day, hou, min, sec, mil)))
00893 print((payload[1].print_format()))
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908 def _waiting_complete(self, text, line, begidx, endidx):
00909 """Get Waiting Command Tab Completion"""
00910
00911
00912 params = self._extract_arguments(line)
00913
00914
00915 if (len(params) == 2 and len(text.strip()) > 0) or \
00916 (len(params) == 1 and len(text.strip()) == 0):
00917 cmds = self.completenames(text)
00918 for cmd in cmds[:]:
00919 if not cmd.startswith('request_'):
00920 cmds.remove(cmd)
00921
00922
00923 return cmds
00924
00925
00926
00927
00928
00929
00930
00931
00932 def emptyline(self):
00933 """Empty Line Action"""
00934
00935 pass
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 def do_help(self, arg):
00946 """syntax: help [<command>]\n""" \
00947 """-- Show the help text for the requested command.\n""" \
00948 """ If command is not specified then list all commands."""
00949
00950
00951 if arg:
00952 return cmd.Cmd.do_help(self, arg)
00953
00954
00955 else:
00956 cmds_cmd = []
00957 cmds_req = []
00958 cmds_hor = []
00959 cmds = []
00960
00961
00962 commands = self.get_names()
00963 commands.sort()
00964
00965
00966 prev = ''
00967 for command in commands:
00968 if command[:3] == 'do_':
00969 if command == prev:
00970 continue
00971 prev = command
00972 command = command[3:]
00973 if len(command) > 8 and command[:8] == 'request_':
00974 cmds_req.append(command)
00975 elif len(command) > 4 and command[:4] == 'set_':
00976 cmds_cmd.append(command)
00977 else:
00978 try:
00979 getattr(self._horizon,command)
00980 cmds_hor.append(command)
00981 except AttributeError:
00982 if command == 'subscribe' or command == 'about' or \
00983 command == 'get_waiting' or command == 'get_time':
00984 cmds_hor.append(command)
00985 else:
00986 cmds.append(command)
00987
00988
00989 self.stdout.write("%s\n"%str(self.doc_leader))
00990 self.print_topics('Horizon', cmds_hor, 15,80)
00991 self.print_topics('Horizon Commands', cmds_cmd,15,80)
00992 self.print_topics('Horizon Requests', cmds_req, 15,80)
00993 self.print_topics('Interactive Shell', cmds, 15,80)
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 def do_about(self, arguments):
01004 """syntax: about \n""" \
01005 """-- Get general info about the Horizon device."""
01006
01007
01008 params = self._extract_arguments(arguments)
01009
01010
01011 if len(params) > 0:
01012 print ("ERROR: Too many arguments!")
01013 return
01014
01015
01016 print((self._about()))
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026 def do_is_alive(self, arguments):
01027 """syntax: is_alive \n""" \
01028 """-- Check if the Horizon device is alive."""
01029
01030
01031 params = self._extract_arguments(arguments)
01032
01033
01034 if len(params) > 0:
01035 print ("ERROR: Too many arguments!")
01036 return
01037
01038
01039 print((self._horizon.alive))
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049 def do_get_time(self, arguments):
01050 """syntax: get_time \n""" \
01051 """-- Get the Horizon device time."""
01052
01053
01054 params = self._extract_arguments(arguments)
01055
01056
01057 if len(params) > 0:
01058 print ("ERROR: Too many arguments!")
01059 return
01060
01061
01062 try:
01063 sec = self._horizon.device_time
01064
01065
01066 mil = sec % 1000
01067 sec = (sec - mil) / 1000
01068 min = sec
01069 sec = min % 60
01070 min = (min - sec) / 60
01071 hou = min
01072 min = hou % 60
01073 hou = (hou - min) / 60
01074 day = hou
01075 hou = day % 24
01076 day = (day - hou) / 24
01077
01078
01079 print(('Time: %02ddays %02dh %02dm %02ds %03dms' \
01080 % (day, hou, min, sec, mil)))
01081
01082
01083 except NotImplementedError:
01084 print ("ERROR: Failed to obtain device time!")
01085 except utils.SubscriptionError:
01086 print ("ERROR: Failed to obtain device time!")
01087 except utils.TimeoutError:
01088 print ("ERROR: Failed to obtain device time!")
01089 except utils.TransportError:
01090 print ("ERROR: Failed to obtain device time!")
01091 except ValueError:
01092 print ("ERROR: Failed to obtain device time!")
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 def do_subscribe(self, arguments):
01103 """syntax: subscribe <frequency> <command>\n""" \
01104 """-- Receive data at <frequency> Hz.\n""" \
01105 """ <frequncy> = off | (1-65534)\n""" \
01106 """ <command> = request command with pertinent arguments"""
01107
01108
01109 params = self._extract_arguments(arguments)
01110
01111
01112 if params == None or len(params) < 2:
01113 print ("ERROR: subscribe invalid number of arguments")
01114 return None
01115
01116
01117 freq = 0xFFFF
01118 if params[0] != 'off' and ((not params[0].isdigit()) or \
01119 int(params[0]) < 1 or int(params[0]) > 65534):
01120 print ("ERROR: Invalid frequency!")
01121 return
01122 elif params[0].isdigit():
01123 freq = int(params[0])
01124
01125
01126 if not params[1] in self.completenames('request_'):
01127 print ("ERROR: Unsupported / Invalid command!")
01128 return
01129 method = None
01130 try:
01131 method = getattr(self._horizon, params[1])
01132 except AttributeError:
01133 print ("ERROR: Unsupported / Invalid command!")
01134 return
01135 args = inspect.getargspec(method)
01136 if not 'subscription' in args[0]:
01137 print(("ERROR: %s does not support subscriptions!" % params[1]))
01138 return
01139
01140
01141 values = self._arguments_to_values(params[2:], method)
01142 if values == None:
01143 return
01144 values['subscription'] = freq
01145
01146
01147 if self._output != None:
01148
01149
01150 if not freq == 0xFFFF:
01151 self._horizon.add_handler(handler=self._handler,
01152 request=params[1])
01153
01154
01155 else:
01156 self._horizon.remove_handler(handler=self._handler,
01157 request=params[1])
01158
01159
01160 try:
01161 res = method(**values)
01162 if res != None:
01163 if isinstance(res, payloads.Payload):
01164 print((res.print_format()))
01165 else:
01166 print (res)
01167 except NotImplementedError:
01168 print(("ERROR: %s is not supported on the platform!" % \
01169 method.__name__))
01170 except utils.SubscriptionError:
01171 print(("ERROR: %s Subscription failed due to frequency!" % \
01172 method.__name__))
01173 except utils.TimeoutError:
01174 print(("ERROR: Timeout occured waiting for %s subscription!" % \
01175 method.__name__))
01176 except utils.TransportError:
01177 print(("ERROR: Transport send for %s subscription failed!" % \
01178 method.__name__))
01179 except ValueError as ex:
01180 print(("ERROR: " + str(ex)))
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195 def complete_subscribe(self, text, line, begidx, endidx):
01196 """Subscribe Command Tab Completion"""
01197
01198
01199 params = self._extract_arguments(line)
01200
01201
01202 if len(params) == 1 and len(text.strip()) == 0:
01203 cmds = list(map(str,list(range(1,65535))))
01204 cmds.insert(0, 'off')
01205 return cmds
01206
01207
01208 elif len(params) == 2 and len(text.strip()) > 0:
01209 params[1] = params[1].rstrip('0')
01210 if params[1] == 'off' or params[1] == 'of' or params[1] == 'o':
01211 return ['off']
01212 elif params[1].isdigit() and int(params[1]) < 65535 and \
01213 int(params[1]) > -1:
01214 cmds = [params[1]]
01215 last = [params[1]]
01216 if len('65535') - len(params[1]) > 1:
01217 for multiple in range(1,len('65535') - len(params[1])):
01218 tmp = []
01219 for cmd in last:
01220 for i in range(0,10):
01221 tmp.append(cmd+str(i))
01222 cmds += tmp
01223 last = tmp
01224 if len('65535') - len(params[1]) > 0:
01225 for cmd in last:
01226 for i in range(0,10):
01227 if int(cmd+str(i)) < 65535:
01228 cmds.append(cmd+str(i))
01229 return cmds
01230 else:
01231 return []
01232
01233
01234 elif (len(params) == 3 and len(text.strip()) > 0) or \
01235 (len(params) == 2 and len(text.strip()) == 0):
01236 cmds = self.completenames(text)
01237 for cmd in cmds[:]:
01238 if not cmd.startswith('request_'):
01239 cmds.remove(cmd)
01240
01241
01242 else:
01243 complete = None
01244 try:
01245 complete = getattr(self, 'complete_' + params[1])
01246 except AttributeError:
01247 complete = self.completedefault
01248 cmds = complete(text, ' '.join(params[1:]), begidx, endidx)
01249
01250
01251 return cmds
01252
01253
01254
01255
01256
01257
01258
01259 def do_repeat(self, arguments):
01260 """usage: repeat [list | off [n] | [frequency command]]\n\n""" \
01261 """Manipulate repeated commands\n\n""" \
01262 """Options: \n""" \
01263 """list ................. Print a numbered list of active repeat commands\n""" \
01264 """off [n] .............. Turn off a given repeat command. [n] is the number provided\n""" \
01265 """ by the list command, the most recent command is removed if \n""" \
01266 """ [n] is not specified.\n""" \
01267 """[frequency] [command] Cause [command] to be executed at [frequency]\n""" \
01268
01269 arguments = arguments.strip()
01270
01271 if arguments == "list":
01272 self._list_repeats()
01273 elif arguments.startswith("off"):
01274 self._remove_repeat(arguments)
01275 else:
01276 self._setup_repeat(arguments)
01277
01278
01279 def _list_repeats(self):
01280 self._cmd_lock.acquire()
01281 try:
01282 if len(self._commands) == 0:
01283 print("No repeat commands are active.")
01284 return
01285
01286 for i in range(len(self._commands)):
01287
01288 cmd_str = "{0}: [{1} Hz]".format(i, self._commands[i][1])
01289 cmd_str += " " + self._commands[i][2][0].func_name
01290 for name in self._commands[i][2][1]:
01291 cmd_str += " {0}={1}".format(name, self._commands[i][2][1][name] )
01292 print(cmd_str)
01293 finally:
01294 self._cmd_lock.release()
01295
01296
01297
01298
01299 def _remove_repeat(self, arguments):
01300 self._cmd_lock.acquire()
01301 try:
01302 if len(self._commands) == 0:
01303 print("No repeat commands are active.")
01304 return
01305
01306
01307 rem_inx = len(self._commands) - 1;
01308
01309
01310 if arguments != "off":
01311
01312
01313 try:
01314 rem_inx = int(arguments[3:])
01315 except ValueError:
01316 print("Index argument is not a valid integer.")
01317 return
01318 if (rem_inx < 0) or (rem_inx >= len(self._commands)):
01319 print("Index argument out of range.")
01320 return
01321
01322
01323 del self._commands[rem_inx]
01324
01325 finally:
01326 self._cmd_lock.release()
01327
01328
01329
01330
01331
01332
01333
01334 def _setup_repeat(self, arguments):
01335
01336 params = self._extract_arguments(arguments)
01337
01338
01339 if params == None or len(params) < 2:
01340 print ("ERROR: repeat: invalid number of arguments")
01341 return None
01342
01343
01344 freq = 0xFFFF
01345 if params[0] != 'off' and ((not params[0].isdigit()) or \
01346 int(params[0]) < 1 or int(params[0]) > 65534):
01347 print ("ERROR: Invalid frequency!")
01348 return
01349 elif params[0].isdigit():
01350 freq = int(params[0])
01351
01352
01353 if not params[1] in self.completenames('set_'):
01354 print ("ERROR: Unsupported command!")
01355 return
01356 method = None
01357 try:
01358 method = getattr(self._horizon, params[1])
01359 except AttributeError:
01360 print ("ERROR: Invalid command!")
01361 return
01362
01363
01364 values = self._arguments_to_values(params[2:], method)
01365 if values == None:
01366 return
01367
01368 if freq == 0xFFFF:
01369 print("Repeat commands may be disabled with 'repeat off [n]'")
01370 return
01371
01372
01373 try:
01374 method(**values)
01375 except NotImplementedError:
01376 print(("ERROR: %s is not supported on the platform!" % \
01377 method.__name__))
01378 except utils.SubscriptionError:
01379 print(("ERROR: %s Subscription failed due to frequency!" % \
01380 method.__name__))
01381 except utils.TimeoutError:
01382 print(("ERROR: Timeout occured waiting for %s subscription!" % \
01383 method.__name__))
01384 except utils.TransportError:
01385 print(("ERROR: Transport send for %s subscription failed!" % \
01386 method.__name__))
01387 except ValueError as ex:
01388 print(("ERROR: " + str(ex)))
01389
01390
01391
01392
01393 timestamp = 0
01394 t = datetime.datetime.today()
01395 timestamp = t.microsecond/1000 + t.second*1000 + \
01396 t.minute*60*1000 + t.hour*60*60*1000 + t.day*24*60*60*1000
01397 while timestamp > 4294967295: timestamp -= 4294967295
01398 timestamp = int(timestamp)
01399
01400
01401 self._cmd_lock.acquire()
01402 self._commands.append(tuple([timestamp,freq,
01403 tuple([method,values])]))
01404 self._cmd_lock.release()
01405
01406
01407 if self._repeating == False:
01408 self._repeating = True
01409 self._repeater.start()
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424 def complete_repeat(self, text, line, begidx, endidx):
01425 """Repeat Command Tab Completion"""
01426
01427
01428 params = self._extract_arguments(line)
01429
01430
01431 if len(params) == 1 and len(text.strip()) == 0:
01432 cmds = list(map(str,list(range(1,65535))))
01433 cmds.insert(0, 'off')
01434 return cmds
01435
01436
01437 elif len(params) == 2 and len(text.strip()) > 0:
01438 params[1] = params[1].rstrip('0')
01439 if params[1] == 'off' or params[1] == 'of' or params[1] == 'o':
01440 return ['off']
01441 elif params[1].isdigit() and int(params[1]) < 65535 and \
01442 int(params[1]) > -1:
01443 cmds = [params[1]]
01444 last = [params[1]]
01445 if len('65535') - len(params[1]) > 1:
01446 for multiple in range(1,len('65535') - len(params[1])):
01447 tmp = []
01448 for cmd in last:
01449 for i in range(0,10):
01450 tmp.append(cmd+str(i))
01451 cmds += tmp
01452 last = tmp
01453 if len('65535') - len(params[1]) > 0:
01454 for cmd in last:
01455 for i in range(0,10):
01456 if int(cmd+str(i)) < 65535:
01457 cmds.append(cmd+str(i))
01458 return cmds
01459 else:
01460 return []
01461
01462
01463 elif (len(params) == 3 and len(text.strip()) > 0) or \
01464 (len(params) == 2 and len(text.strip()) == 0):
01465 cmds = self.completenames(text)
01466 for cmd in cmds[:]:
01467 if not cmd.startswith('set_'):
01468 cmds.remove(cmd)
01469
01470
01471 else:
01472 complete = None
01473 try:
01474 complete = getattr(self, 'complete_' + params[1])
01475 except AttributeError:
01476 complete = self.completedefault
01477 cmds = complete(text, ' '.join(params[1:]), begidx, endidx)
01478
01479
01480 return cmds
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492 def do_quit(self, arg):
01493 """syntax: quit""" \
01494 """-- Exit the Interactive Shell."""
01495
01496
01497 return True
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509 def do_exit(self, arg):
01510 """syntax: exit""" \
01511 """-- Because quit just isn't enough."""
01512
01513
01514 return True
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526 def do_EOF(self, arg):
01527 """syntax: ^d""" \
01528 """-- Because quit and exit just aren't enough."""
01529
01530
01531 print ("exit")
01532
01533
01534 return True
01535
01536
01537 logger.debug("... clearpath.horizon.demo loaded.")
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560 def __main():
01561 """Bootstrap the basic Horizon Demo."""
01562
01563
01564 while len(horizon_logger.handlers) > 0:
01565 horizon_logger.removeHandler(horizon_logger.handlers[0])
01566 while len(logger.handlers) > 0:
01567 logger.removeHandler(logger.handlers[0])
01568 logger_handler = logging.StreamHandler()
01569 logger_handler.setFormatter(
01570 logging.Formatter("%(levelname)s: %(message)s"))
01571 horizon_logger.addHandler(logger_handler)
01572 horizon_logger.setLevel(logging.WARNING)
01573 logger.propagate = True
01574
01575
01576 ver_re = re.compile(r'^-v$')
01577 for arg in sys.argv[1:]:
01578 if ver_re.match(arg):
01579 horizon_logger.setLevel(logging.INFO)
01580 logger.info("Verbose mode entered.")
01581 break
01582
01583
01584 logger.info("Looking for serial ports...")
01585 ports = []
01586 try:
01587 serial
01588 ports = utils.list_serial_ports()
01589 except OSError as ex:
01590 logging.critical(ex)
01591 sys.exit(1)
01592 except IOError as ex:
01593 logging.critical(ex)
01594 sys.exit(1)
01595 except NameError:
01596 logger.warning("Serial not supported. Please install pySerial.")
01597 if len(ports) > 0:
01598 ports.sort()
01599 logger.info("...located %d serial ports: %s" %(len(ports),
01600 ', '.join(ports)))
01601
01602
01603 logger.info("Parsing command-line arguments...")
01604 usage = 'usage: python -m clearpath.horizon.demo [<device>] [options]\n\n'
01605 try:
01606 serial
01607 if len(ports) == 0: raise NameError("")
01608 usage = usage + '<device> = <serial> | (tcp | udp):<address>\n' + \
01609 '<serial> = ' + ' | '.join(ports) + '\n'
01610 except NameError:
01611 usage = usage + '<device> = (tcp | udp):<address>\n'
01612 usage = usage + '<address> = <host>:<port>\n' + \
01613 '<host> = computer hostname or IP address\n' + \
01614 '<port> = computer port number (1-65535)'
01615 desc = 'Horizon Basic Command-Line Controller: Interactively control a ' + \
01616 'Horizon device connected at <device>.'
01617 vers = 'Horizon Protocol Document version to communicate with. ' + \
01618 'Supported version(s): '
01619 ver = []
01620 p = optparse.OptionParser(usage=usage,description=desc)
01621 p.add_option('--output', '-o', action='store', type='str', metavar='FILE',
01622 default='/dev/null', help='Location to send subscription '\
01623 'data. Default location (/dev/null) enables "get_waiting" '\
01624 'command. To watch the results in real-time, use the "tail '\
01625 '-F" command on this file.')
01626 p.add_option('--verbose', '-v', action='count',
01627 help='Print detailed messages. Use twice for debug messages.')
01628 p.add_option('--debug_messages', action='store', type='choice',
01629 choices=['DEBUG','INFO','WARNING','ERROR','NONE'],
01630 help='Select the debug level for messages.py. '\
01631 'INFO is useful for general debug and DEBUG is useful for' \
01632 ' crash location detection. This flag automatically enables'\
01633 ' verbose debug messages (-v -v) regardless of LEVEL.')
01634 p.add_option('--debug_payloads', action='store', type='choice',
01635 choices=['DEBUG','INFO','WARNING','ERROR','NONE'],
01636 help='Select the debug level for payloads.py. '\
01637 'INFO is useful for general debug and DEBUG is useful for' \
01638 ' crash location detection. This flag automatically enables'\
01639 ' verbose debug messages (-v -v) regardless of LEVEL.')
01640 p.add_option('--debug_protocol', action='store', type='choice',
01641 choices=['DEBUG','INFO','WARNING','ERROR','NONE'],
01642 help='Select the debug level for protocol.py. '\
01643 'INFO is useful for general debug and DEBUG is useful for' \
01644 ' crash location detection. This flag automatically enables'\
01645 ' verbose debug messages (-v -v) regardless of LEVEL.')
01646 p.add_option('--debug_transports', action='store', type='choice',
01647 choices=['DEBUG','INFO','WARNING','ERROR','NONE'],
01648 help='Select the debug level for transports.py. '\
01649 'INFO is useful for general debug and DEBUG is useful for' \
01650 ' crash location detection. This flag automatically enables'\
01651 ' verbose debug messages (-v -v) regardless of LEVEL.')
01652 p.add_option('--doc', action='store_true',
01653 help='Access the latest Horizon specification document ')
01654 encr = []
01655 try:
01656 Crypto.Random
01657 try:
01658 Crypto.Cipher.AES
01659 encr += ['AES']
01660 except NameError:
01661 pass
01662 try:
01663 Crypto.Cipher.Blowfish
01664 encr += ['Blowfish']
01665 except NameError:
01666 pass
01667 try:
01668 Crypto.Cipher.CAST
01669 encr += ['CAST']
01670 except NameError:
01671 pass
01672 try:
01673 Crypto.Cipher.DES
01674 encr += ['DES']
01675 except NameError:
01676 pass
01677 try:
01678 Crypto.Cipher.DES3
01679 encr += ['DES3']
01680 except NameError:
01681 pass
01682 try:
01683 Crypto.Cipher.ARC2
01684 encr += ['RC2']
01685 except NameError:
01686 pass
01687 p.add_option('--encryption', action='store', type='choice',
01688 choices=encr,
01689 help='Select the encryption cipher to use for TCP '\
01690 'communication ['+', '.join(encr)+']. '\
01691 'Not all choices may be available; refer to '\
01692 '`python -m clearpath.horizon.demo --doc` for details.',
01693 metavar='CIPHER')
01694 p.add_option('--key', action='store',type='str', metavar='KEY',
01695 help='The encryption key to use with --encryption. '\
01696 'The key length is dependent upon the chosen cipher.')
01697 except NameError:
01698 pass
01699 p.add_option('--version', action='store', type='str', metavar='VER',
01700 default='0.0', help=vers)
01701 options, arguments = p.parse_args()
01702 logger.info("...command-line arguments parsed.")
01703
01704
01705 if options.doc:
01706 logger.info("Documentation flag found: Launching documentation...")
01707 loc = __file__.rstrip('demo.py')+'doc/'
01708 if os.system("man -l "+loc+"horizon.3") != 0:
01709 if os.system("less "+loc+"horizon.txt") != 0:
01710 os.system("cat "+loc+"horizon.txt")
01711 sys.exit(0)
01712
01713
01714 if len(arguments) > 1:
01715 p.print_usage()
01716 sys.stderr.write("horizon_demo.py: error: too many arguments\n")
01717 sys.exit(1)
01718
01719
01720 addr_re1 = re.compile(r'^((?:[a-zA-Z0-9]+' \
01721 '(?:[a-zA-Z0-9\\-]+[a-zA-Z0-9])?)' \
01722 '(?:\\.(?:[a-zA-Z0-9]+(?:[a-zA-Z0-9\\-]+[a-zA-Z0-9]'\
01723 ')?))*):([1-9][0-9]{0,4})$')
01724 addr_re2 = re.compile(r'^((?:[a-zA-Z0-9\\-]{1,63})' \
01725 '(?:\\.(?:[a-zA-Z0-9\\-]' \
01726 '{1,63}))*):([1-9][0-9]{0,4})$')
01727 addr_re3 = re.compile(r'^([a-zA-Z0-9\\-\\.]{1,255}):' \
01728 '((?:6553[0-5])|(?:655' \
01729 '[0-2][0-9])|(?:65[0-4][0-9]{2})|(?:6[0-4][0-9]{3})'\
01730 '|(?:[1-5][0-9]{4})|(?:[1-9][0-9]{0,3}))$')
01731
01732
01733 if options.debug_messages != None or options.debug_payloads != None or \
01734 options.debug_protocol != None or options.debug_transports != None:
01735 logger_handler.setFormatter(logging.Formatter(
01736 "%(name)s: %(levelname)s: %(message)s"))
01737 horizon_logger.setLevel(logging.DEBUG)
01738 logger.info("Debug mode entered.")
01739 if options.debug_messages != None:
01740 messages.logger.propagate = True
01741 if options.debug_messages == 'DEBUG':
01742 messages.logger.setLevel(logging.DEBUG)
01743 elif options.debug_messages == 'INFO':
01744 messages.logger.setLevel(logging.INFO)
01745 elif options.debug_messages == 'WARNING':
01746 messages.logger.setLevel(logging.WARNING)
01747 elif options.debug_messages == 'ERROR':
01748 messages.logger.setLevel(logging.ERROR)
01749 else:
01750 messages.logger.propagate = False
01751 if options.debug_payloads != None:
01752 payloads.logger.propagate = True
01753 if options.debug_payloads == 'DEBUG':
01754 payloads.logger.setLevel(logging.DEBUG)
01755 elif options.debug_payloads == 'INFO':
01756 payloads.logger.setLevel(logging.INFO)
01757 elif options.debug_payloads == 'WARNING':
01758 payloads.logger.setLevel(logging.WARNING)
01759 elif options.debug_payloads == 'ERROR':
01760 payloads.logger.setLevel(logging.ERROR)
01761 else:
01762 payloads.logger.propagate = False
01763 if options.debug_protocol != None:
01764 protocol.logger.propagate = True
01765 if options.debug_protocol == 'DEBUG':
01766 protocol.logger.setLevel(logging.DEBUG)
01767 elif options.debug_protocol == 'INFO':
01768 protocol.logger.setLevel(logging.INFO)
01769 elif options.debug_protocol == 'WARNING':
01770 protocol.logger.setLevel(logging.WARNING)
01771 elif options.debug_protocol == 'ERROR':
01772 protocol.logger.setLevel(logging.ERROR)
01773 else:
01774 protocol.logger.propagate = False
01775 if options.debug_transports != None:
01776 transports.logger.propagate = True
01777 if options.debug_transports == 'DEBUG':
01778 transports.logger.setLevel(logging.DEBUG)
01779 elif options.debug_transports == 'INFO':
01780 transports.logger.setLevel(logging.INFO)
01781 elif options.debug_transports == 'WARNING':
01782 transports.logger.setLevel(logging.WARNING)
01783 elif options.debug_transports == 'ERROR':
01784 transports.logger.setLevel(logging.ERROR)
01785 else:
01786 transports.logger.propagate = False
01787 elif options.verbose != None and options.verbose > 1:
01788 horizon_logger.setLevel(logging.DEBUG)
01789 logger.info("Debug mode entered.")
01790
01791 transport = None
01792 transport_args = {}
01793
01794 if len(arguments) == 0:
01795
01796 transport = transports.Serial.autodetect
01797
01798 else:
01799
01800 transport = transports.Serial
01801 transport_args = {'port':arguments[0]}
01802 logger.info("Using serial port %s." % arguments[0])
01803
01804
01805 if transport == None:
01806 p.print_usage()
01807 sys.stderr.write("error: invalid device specified\n")
01808 sys.exit(1)
01809
01810
01811 output = ''
01812 if options.output != '/dev/null' and (os.path.isdir(output) or \
01813 (os.path.isfile(output) and not os.access(output, os.R_OK|os.W_OK))\
01814 or (not os.path.lexists(output) and not os.access(
01815 os.path.dirname(os.path.abspath(output)), os.R_OK|os.W_OK))):
01816 p.print_usage()
01817 ex = "error: option --output: inaccessible value"
01818 sys.stderr.write(ex + '\n')
01819 sys.exit(1)
01820 else:
01821 if options.output != '/dev/null': output = options.output
01822 if output != '':
01823 logger.info("Saving subscription data to '%s'." % output)
01824
01825
01826 horizon = None
01827 command = None
01828 err = 0
01829 try:
01830
01831
01832 logger.debug("Initializing Horizon Interface...")
01833 horizon = Horizon(transport=transport,
01834 transport_args=transport_args)
01835 logger.debug("...Horizon Interface Initialized.")
01836
01837
01838 logger.debug("Opening Communications...")
01839 horizon.open()
01840 logger.debug("...Communications Open.")
01841
01842
01843 command = HorizonDemo(port=str(horizon),
01844 horizon=horizon,
01845 output=output)
01846 logger.debug("Entering shell...")
01847 histfile = os.path.join(os.environ["HOME"], ".cprcli_history")
01848 try:
01849 readline.read_history_file(histfile)
01850 except IOError:
01851
01852 pass
01853
01854 readline.set_history_length(100)
01855 command.cmdloop()
01856 readline.write_history_file(histfile)
01857 logger.debug("...shell exited.")
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868 except KeyboardInterrupt:
01869 print ("")
01870 logger.debug("...shell exited.")
01871
01872
01873
01874
01875
01876
01877
01878 finally:
01879 if horizon != None:
01880 logger.debug("Closing Communications...")
01881 horizon.close()
01882 logger.debug("...Communications Closed.")
01883
01884
01885 logger.info("Program Complete!")
01886 sys.exit(err)
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896 if __name__ == "__main__":
01897
01898
01899 __main()
01900
01901
01902 sys.exit(1)