diff options
Diffstat (limited to 'nxt_plugin/nxt/locator.py')
-rw-r--r-- | nxt_plugin/nxt/locator.py | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/nxt_plugin/nxt/locator.py b/nxt_plugin/nxt/locator.py new file mode 100644 index 0000000..46b5ec8 --- /dev/null +++ b/nxt_plugin/nxt/locator.py @@ -0,0 +1,177 @@ +# nxt.locator module -- Locate LEGO Minstorms NXT bricks via USB or Bluetooth +# Copyright (C) 2006, 2007 Douglas P Lau +# Copyright (C) 2009 Marcus Wanner +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +import traceback, ConfigParser, os + +class BrickNotFoundError(Exception): + pass + +class NoBackendError(Exception): + pass + +class Method(): + """Used to indicate which comm backends should be tried by find_bricks/ +find_one_brick. Any or all can be selected.""" + def __init__(self, usb=True, bluetooth=True, fantomusb=False, fantombt=False): + #new method options MUST default to False! + self.usb = usb + self.bluetooth = bluetooth + self.fantom = fantomusb or fantombt + self.fantomusb = fantomusb + self.fantombt = fantombt + +def find_bricks(host=None, name=None, silent=False, method=Method()): + """Used by find_one_brick to look for bricks ***ADVANCED USERS ONLY***""" + methods_available = 0 + + if method.usb: + try: + import usbsock + methods_available += 1 + socks = usbsock.find_bricks(host, name) + for s in socks: + yield s + except ImportError: + import sys + if not silent: print >>sys.stderr, "USB module unavailable, not searching there" + + if method.bluetooth: + try: + import bluesock + methods_available += 1 + try: + socks = bluesock.find_bricks(host, name) + for s in socks: + yield s + except (bluesock.bluetooth.BluetoothError, IOError): #for cases such as no adapter, bluetooth throws IOError, not BluetoothError + pass + except ImportError: + import sys + if not silent: print >>sys.stderr, "Bluetooth module unavailable, not searching there" + + if method.fantom: + try: + import fantomsock + methods_available += 1 + if method.fantomusb: + usbsocks = fantomsock.find_bricks(host, name, False) + for s in usbsocks: + yield s + if method.fantombt: + btsocks = fantomsock.find_bricks(host, name, True) + for s in btsocks: + yield s + except ImportError: + import sys + if not silent: print >>sys.stderr, "Fantom module unavailable, not searching there" + + if methods_available == 0: + raise NoBackendError("No selected backends are available! Did you install the comm modules?") + + +def find_one_brick(host=None, name=None, silent=False, strict=None, debug=False, method=None, confpath=None): + """Use to find one brick. The host and name args limit the search to +a given MAC or brick name. Set silent to True to stop nxt-python from +printing anything during the search. This function by default +automatically checks to see if the brick found has the correct host/name +(if either are provided) and will not return a brick which doesn't +match. This can be disabled (so the function returns any brick which can +be connected to and provides a valid reply to get_device_info()) by +passing strict=False. This will, however, still tell the comm backends +to only look for devices which match the args provided. The confpath arg +specifies the location of the configuration file which brick location +information will be read from if no brick location directives (host, +name, strict, or method) are provided.""" + if debug and silent: + silent=False + print "silent and debug can't both be set; giving debug priority" + + conf = read_config(confpath, debug) + if not (host or name or strict or method): + host = conf.get('Brick', 'host') + name = conf.get('Brick', 'name') + strict = bool(int(conf.get('Brick', 'strict'))) + method = eval('Method(%s)' % conf.get('Brick', 'method')) + if not strict: strict = True + if not method: method = Method() + if debug: + print "Host: %s Name: %s Strict: %s" % (host, name, str(strict)) + print "USB: %s BT: %s Fantom: %s FUSB: %s FBT: %s" % (method.usb, method.bluetooth, method.fantom, method.fantombt, method.fantomusb) + + for s in find_bricks(host, name, silent, method): + try: + if host and 'host' in dir(s) and s.host != host: + if debug: + print "Warning: the brick found does not match the host provided (s.host)." + if strict: continue + b = s.connect() + info = b.get_device_info() + if host and info[1] != host: + if debug: + print "Warning: the brick found does not match the host provided (get_device_info)." + if strict: + s.close() + continue + if name and info[0].strip('\0') != name: + if debug: + print "Warning; the brick found does not match the name provided." + if strict: + s.close() + continue + return b + except: + if debug: + traceback.print_exc() + print "Failed to connect to possible brick" + #raise BrickNotFoundError + + +def server_brick(host, port = 2727): + import ipsock + sock = ipsock.IpSock(host, port) + return sock.connect() + + +def read_config(confpath=None, debug=False): + conf = ConfigParser.RawConfigParser({'host': None, 'name': None, 'strict': True, 'method': ''}) + if not confpath: confpath = os.path.expanduser('~/.nxt-python') + if conf.read([confpath]) == [] and debug: + print "Warning: Config file (should be at %s) was not read. Use nxt.locator.make_config() to create a config file." % confpath + if conf.has_section('Brick') == False: + conf.add_section('Brick') + return conf + +def make_config(confpath=None): + conf = ConfigParser.RawConfigParser() + if not confpath: confpath = os.path.expanduser('~/.nxt-python') + print "Welcome to the nxt-python config file generator!" + print "This function creates an example file which find_one_brick uses to find a brick." + try: + if os.path.exists(confpath): raw_input("File already exists at %s. Press Enter to overwrite or Ctrl+C to abort." % confpath) + except KeyboardInterrupt: + print "Not writing file." + return + conf.add_section('Brick') + conf.set('Brick', 'name', 'MyNXT') + conf.set('Brick', 'host', '54:32:59:92:F9:39') + conf.set('Brick', 'strict', 0) + conf.set('Brick', 'method', 'usb=True, bluetooth=False, fantomusb=True') + conf.write(open(confpath, 'w')) + print "The file has been written at %s" % confpath + print "The file contains less-than-sane default values to get you started." + print "You must now edit the file with a text editor and change the values to match what you would pass to find_one_brick" + print "The fields for name, host, and strict correspond to the similar args accepted by find_one_brick" + print "The method field contains the string which would be passed to Method()" + print "Any field whose corresponding option does not need to be passed to find_one_brick should be commented out (using a # at the start of the line) or simply removed." + print "If you have questions, check the wiki and then ask on the mailing list." |