source: trunk/Puzzlebox/Synapse/Device.py @ 402

Last change on this file since 402 was 402, checked in by sc, 8 years ago
  • serial device recognition under Darwin added
File size: 11.9 KB
Line 
1# -*- coding: utf-8 -*-
2
3# Copyright Puzzlebox Productions, LLC (2010-2012)
4#
5# This code is released under the GNU Pulic License (GPL) version 2
6# For more information please refer to http://www.gnu.org/copyleft/gpl.html
7
8__changelog__ = """\
9Last Update: 2012.04.23
10"""
11
12__todo__ = """
13"""
14
15### IMPORTS ###
16import os, sys
17
18import Puzzlebox.Synapse.Configuration as configuration
19
20if configuration.ENABLE_PYSIDE:
21        try:
22                import PySide as PyQt4
23                from PySide import QtCore, QtGui
24        except Exception, e:
25                print "ERROR: [Synapse:Device] Exception importing PySide:",
26                print e
27                configuration.ENABLE_PYSIDE = False
28        else:
29                print "INFO: [Synapse:Device] Using PySide module"
30
31if not configuration.ENABLE_PYSIDE:
32        print "INFO: [Synapse:Device] Using PyQt4 module"
33        from PyQt4 import QtCore, QtGui
34
35if (sys.platform == 'win32'):
36        import _winreg as winreg
37        import itertools
38        import re
39        import serial
40        DEFAULT_IMAGE_PATH = 'images'
41elif (sys.platform == 'darwin'):
42        DEFAULT_IMAGE_PATH = 'images'
43else:
44        import bluetooth
45        DEFAULT_IMAGE_PATH = '/usr/share/puzzlebox_synapse/images'
46
47
48#####################################################################
49# Globals
50#####################################################################
51
52DEBUG = configuration.DEBUG
53
54PATH_TO_HCITOOL = '/usr/bin/hcitool'
55
56
57#####################################################################
58# Classes
59#####################################################################
60
61class puzzlebox_synapse_device(QtGui.QWidget):
62       
63        def __init__(self, log, \
64                     DEBUG=DEBUG, \
65                     parent=None, \
66                     ):
67               
68                self.log = log
69                self.DEBUG = DEBUG
70                self.parent=parent
71               
72                if self.parent == None:
73                        QtGui.QWidget.__init__(self, parent)
74                        #self.setupUi(self)
75               
76                        self.configureSettings()
77                        self.connectWidgets()
78               
79                self.name = "Synapse:Device"
80       
81       
82        ##################################################################
83       
84        def configureSettings(self):
85               
86                pass
87       
88       
89        ##################################################################
90       
91        def connectWidgets(self):
92               
93                pass
94       
95       
96        ##################################################################
97       
98        def enumerateSerialPorts(self):
99               
100                """ Uses the Win32 registry to return an
101                iterator of serial (COM) ports
102                existing on this computer.
103               
104                from http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
105                """
106         
107                path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
108                try:
109                        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
110                except WindowsError:
111                        #raise IterationError
112                        return
113               
114                for i in itertools.count():
115                        try:
116                                val = winreg.EnumValue(key, i)
117                                yield str(val[1])
118                        except EnvironmentError:
119                                break
120       
121       
122        ##################################################################
123       
124        def fullPortName(self, portname):
125               
126                """ Given a port-name (of the form COM7,
127                COM12, CNCA0, etc.) returns a full
128                name suitable for opening with the
129                Serial class.
130                """
131               
132                m = re.match('^COM(\d+)$', portname)
133                if m and int(m.group(1)) < 10:
134                        return portname
135               
136                return '\\\\.\\' + portname
137       
138       
139        ##################################################################
140       
141        def searchForSerialDevices(self, devices=[]):
142               
143                if (sys.platform == 'win32'):
144                       
145                        for portname in self.enumerateSerialPorts():
146                               
147                                if portname not in devices:
148                                        #portname = self.fullPortName(portname)
149                                        devices.append(portname)
150               
151               
152                elif (sys.platform == 'darwin'):
153                 
154                  for device in os.listdir('/dev'):
155                         if (device.startswith('tty.MindWaveMobile') or \
156                             device.startswith('tty.MindWave')):
157                                         
158                                         devices.append( os.path.join('/dev', device))
159                       
160                       
161                  # Handle MindSet separately so it shows up second in listings
162                  for device in os.listdir('/dev'):
163                         if (device.startswith('tty.MindSet')):
164                                         
165                                         devices.append( os.path.join('/dev', device))
166               
167                else:
168                       
169                        #if os.path.exists('/dev/tty.MindWaveMobile-SPPDev'):
170                                #devices.append('/dev/tty.MindWaveMobile-SPPDev')
171                        #if os.path.exists('/dev/tty.MindWaveMobile-DevA'):
172                                #devices.append('/dev/tty.MindWaveMobile-DevA')
173                        #if os.path.exists('/dev/tty.MindWaveMobile-DevB'):
174                                #devices.append('/dev/tty.MindWaveMobile-DevB')
175                       
176                        #if os.path.exists('/dev/tty.MindWave'):
177                                #devices.append('/dev/tty.MindWave')
178                        #if os.path.exists('/dev/tty.MindWave1'):
179                                #devices.append('/dev/tty.MindWave1')
180                        #if os.path.exists('/dev/tty.MindWave2'):
181                                #devices.append('/dev/tty.MindWave2')
182                        #if os.path.exists('/dev/tty.MindWave3'):
183                                #devices.append('/dev/tty.MindWave3')
184                        #if os.path.exists('/dev/tty.MindWave4'):
185                                #devices.append('/dev/tty.MindWave4')
186                        #if os.path.exists('/dev/tty.MindWave5'):
187                                #devices.append('/dev/tty.MindWave5')
188                       
189                        #if os.path.exists('/dev/tty.MindSet-DevB'):
190                                #devices.append('/dev/tty.MindSet-DevB')
191                       
192                       
193                  for device in os.listdir('/dev'):
194                         if (device.startswith('ttyUSB') or \
195                             device.startswith('ttyACM') or \
196                             device.startswith('tty.usbserial') or \
197                             device.startswith('rfcomm')):
198                                         
199                                         devices.append( os.path.join('/dev', device))
200                       
201                        #if os.path.exists('/dev/ttyUSB0'):
202                                #devices.append('/dev/ttyUSB0')
203                        #if os.path.exists('/dev/ttyUSB1'):
204                                #devices.append('/dev/ttyUSB1')
205                        #if os.path.exists('/dev/ttyUSB2'):
206                                #devices.append('/dev/ttyUSB2')
207                        #if os.path.exists('/dev/ttyUSB3'):
208                                #devices.append('/dev/ttyUSB3')
209                        #if os.path.exists('/dev/ttyUSB4'):
210                                #devices.append('/dev/ttyUSB4')
211                        #if os.path.exists('/dev/ttyUSB5'):
212                                #devices.append('/dev/ttyUSB5')
213                        #if os.path.exists('/dev/ttyUSB6'):
214                                #devices.append('/dev/ttyUSB6')
215                        #if os.path.exists('/dev/ttyUSB7'):
216                                #devices.append('/dev/ttyUSB7')
217                        #if os.path.exists('/dev/ttyUSB8'):
218                                #devices.append('/dev/ttyUSB8')
219                        #if os.path.exists('/dev/ttyUSB9'):
220                                #devices.append('/dev/ttyUSB9')
221                       
222                        #if os.path.exists('/dev/rfcomm0'):
223                                #devices.append('/dev/rfcomm0')
224                        #if os.path.exists('/dev/rfcomm1'):
225                                #devices.append('/dev/rfcomm1')
226                        #if os.path.exists('/dev/rfcomm2'):
227                                #devices.append('/dev/rfcomm2')
228                        #if os.path.exists('/dev/rfcomm3'):
229                                #devices.append('/dev/rfcomm3')
230                        #if os.path.exists('/dev/rfcomm4'):
231                                #devices.append('/dev/rfcomm4')
232                       
233                        #if os.path.exists('/dev/ttyACM0'):
234                                #devices.append('/dev/ttyACM0')
235                        #if os.path.exists('/dev/ttyACM1'):
236                                #devices.append('/dev/ttyACM1')
237                        #if os.path.exists('/dev/ttyACM2'):
238                                #devices.append('/dev/ttyACM2')
239                        #if os.path.exists('/dev/ttyACM3'):
240                                #devices.append('/dev/ttyACM3')
241                        #if os.path.exists('/dev/ttyACM4'):
242                                #devices.append('/dev/ttyACM4')
243               
244               
245                return(devices)
246       
247       
248        ##################################################################
249       
250        def hcitoolScanForRemoteDevices(self, devices=[]):
251               
252                bluetooth_devices = []
253               
254                #command = '%s scan 2> /dev/null' % PATH_TO_HCITOOL
255                command = '%s scan' % PATH_TO_HCITOOL
256               
257                if self.DEBUG > 1:
258                        print 'INFO: Calling "%s"' % command
259               
260                output = os.popen(command, 'r')
261               
262                try:
263                        result = output.readlines()
264                except Exception, e:
265                        if self.DEBUG:
266                                print "ERROR [Synapse-Interface]: Failed reading result from call to hcitool:",
267                                print e
268                        result = ''
269               
270                if result == '':
271                        return([]) # Under OS X hcitool doesn't exist so we don't see any devices
272               
273                for line in result:
274                        line = line.strip()
275                        if line == '' or line == 'Scanning ...':
276                                continue
277                        elif self.DEBUG > 1:
278                                print line
279                        try:
280                                address = line.split('\t')[0]
281                        except:
282                                pass
283                        else:
284                                bluetooth_devices.append(address)
285               
286               
287                for address in bluetooth_devices:
288                       
289                        command = '%s name %s' % (PATH_TO_HCITOOL, address)
290                       
291                        if self.DEBUG:
292                                print 'INFO: Calling "%s"' % command
293                       
294                        output = os.popen(command, 'r')
295                       
296                        for line in output.readlines():
297                                line = line.strip()
298                                if line == '':
299                                        continue
300                                elif self.DEBUG:
301                                        print '\t',
302                                        print line
303                               
304                                device_name = line.strip()
305                       
306                                if ((device_name == 'MindSet' or device_name == 'MindWave Mobile') and \
307                                        (address not in devices)):
308                                        devices.append(address)
309                               
310                                else:
311                                        if self.DEBUG:
312                                                print 'INFO: Found but not recognized: [%s] %s' % \
313                                                        (address, device_name)
314               
315               
316                return (devices)
317       
318       
319        ##################################################################
320       
321        def hcitoolGetActiveConnections(self, devices=[]):
322               
323                bluetooth_devices = []
324               
325                #command = '%s con 2> /dev/null' % PATH_TO_HCITOOL
326                command = '%s con' % PATH_TO_HCITOOL
327               
328                if self.DEBUG > 1:
329                        print 'INFO: Calling "%s"' % command
330               
331                output = os.popen(command, 'r')
332               
333                try:
334                        result = output.readlines()
335                except Exception, e:
336                        if self.DEBUG:
337                                print "ERROR [Synapse:Interface]: Failed reading result from call to hcitool:",
338                                print e
339                        result = ''
340
341                if result == '':
342                        return([]) # Under OS X hcitool doesn't exist so we don't see any devices
343
344                for line in result:
345                        line = line.strip()
346                        if line == '' or line == 'Connections:':
347                                continue
348                        elif self.DEBUG > 1:
349                                print line
350                        try:
351                                address = line.split(' ')[2]
352                        except:
353                                pass
354                        else:
355                                bluetooth_devices.append(address)
356               
357               
358                for address in bluetooth_devices:
359                       
360                        command = '%s name %s' % (PATH_TO_HCITOOL, address)
361                       
362                        if self.DEBUG:
363                                print 'INFO: Calling "%s":' % command
364                       
365                        output = os.popen(command, 'r')
366                       
367                        for line in output.readlines():
368                                line = line.strip()
369                                if line == '':
370                                        continue
371                                elif self.DEBUG:
372                                        print '\t',
373                                        print line
374                               
375                                device_name = line.strip()
376                       
377                                if ((device_name == 'MindSet' or device_name == 'MindWave Mobile') and \
378                                        (address not in devices)):
379                                        devices.append(address)
380               
381               
382                return (devices)
383       
384       
385        ##################################################################
386       
387        def searchForDevices(self):
388               
389                enable_hcitool = configuration.ENABLE_HCITOOL
390               
391                devices = []
392               
393                #self.pushButtonBluetoothSearch.setText('Searching')
394               
395                if ((sys.platform != 'win32' and sys.platform != 'darwin') and \
396                     configuration.THINKGEAR_BLUETOOTH_SEARCH):
397                       
398                        # Bluetooth module doesn't compile properly under Windows
399                        # and doesn't exist under OS X
400                       
401                        # PyBluez API Documentation
402                        # http://pybluez.googlecode.com/svn/www/docs-0.7/index.html
403                       
404                        bluetooth_devices = []
405                       
406                        if not enable_hcitool:
407                               
408                                try:
409                                       
410                                        if self.DEBUG:
411                                                print "INFO: Searching for Bluetooth devices using PyBluez module"
412                                       
413                                        bluetooth_devices = bluetooth.discover_devices( \
414                                              duration=configuration.THINKGEAR_BLUETOOTH_DISCOVER_DEVICES_TIMEOUT, \
415                                                               flush_cache=True, \
416                                                               lookup_names=False)
417                                       
418                                        for address in bluetooth_devices:
419                                               
420                                                if self.DEBUG:
421                                                        print "INFO: Device discovered",
422                                                        print address
423                                               
424                                                device_name = bluetooth.lookup_name(address, \
425                                                                 configuration.THINKGEAR_BLUETOOTH_LOOKUP_NAME_TIMEOUT)
426                                                if ((device_name == 'MindSet' or device_name == 'MindWave Mobile') and \
427                                                        (address not in devices)):
428                                                        devices.append(address)
429                                       
430                                       
431                                        # There is an issue under recent released of Linux
432                                        # in which already-connected Bluetooth ThinkGear devices
433                                        # are not appearing in a bluetooth device scan. However,
434                                        # using "hcitool" connected devices can be listed correctly.
435                                        # There does not appear to be an equivalent PyBluez feature.
436                                        # (http://pybluez.googlecode.com/svn/www/docs-0.7/index.html)
437                                       
438                                        if devices == []:
439                                                if self.DEBUG:
440                                                        print "INFO: No devices found through PyBluez module. Falling back to hcitool."
441                                                devices = self.hcitoolGetActiveConnections(devices)
442                               
443                               
444                                except Exception, e:
445                                        if self.DEBUG:
446                                                print "ERROR: Exception calling Python Bluetooth module. (Is PyBluez installed?):"
447                                                print e
448                                       
449                                       
450                                        #if (sys.platform != 'darwin'):
451                                        enable_hcitool = True
452                       
453                       
454                        if enable_hcitool:
455                               
456                                devices = self.hcitoolScanForRemoteDevices(devices)
457                                devices = self.hcitoolGetActiveConnections(devices)
458                       
459                       
460                        if self.DEBUG > 2:
461                                print "Bluetooth Devices found:",
462                                print devices
463               
464               
465                devices = self.searchForSerialDevices(devices)
466               
467               
468                if self.DEBUG:
469                        print "Devices found:",
470                        print devices
471               
472               
473                return(devices)
474
Note: See TracBrowser for help on using the repository browser.