source: trunk/Puzzlebox/Synapse/Interface.py @ 283

Last change on this file since 283 was 283, checked in by sc, 10 years ago

Server:

  • cleaned up handling of disconnected sockets

Interface:

  • save/export data to platform-specific home directory by default
  • initial support for customDataHeaders
  • subclass/parent data access support added
  • Property svn:executable set to *
File size: 30.2 KB
Line 
1# -*- coding: utf-8 -*-
2
3# Copyright Puzzlebox Productions, LLC (2010-2011)
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# Old Class Names:
9#       puzzlebox_synapse_interface = QtUI
10
11__changelog__ = """\
12Last Update: 2011.08.23
13"""
14
15__todo__ = """
16- update configuration.ini file with settings entered into interface
17
18"""
19
20### IMPORTS ###
21import os, sys, time
22import simplejson as json
23
24try:
25        from Interface_Plot import *
26        MATPLOTLIB_AVAILABLE = True
27except:
28        MATPLOTLIB_AVAILABLE = False
29
30if (sys.platform != 'win32'):
31        import bluetooth
32        DEFAULT_IMAGE_PATH = '/usr/share/puzzlebox_synapse/images'
33else:
34        import _winreg as winreg
35        import itertools
36        import re
37        import serial
38        DEFAULT_IMAGE_PATH = 'images'
39
40try:
41        import PySide as PyQt4
42        from PySide import QtCore, QtGui
43except:
44        print "Using PyQt4 module"
45        from PyQt4 import QtCore, QtGui
46else:
47        print "Using PySide module"
48
49try:
50        import cPickle as pickle
51except:
52        import pickle
53
54# from puzzlebox_synapse_interface_design import Ui_Form
55from Interface_Design import Ui_Form as Design
56
57import Configuration as configuration
58import Server as synapse_server
59import Client as thinkgear_client
60#import puzzlebox_logger
61
62### GLOBALS ###
63
64DEBUG = 1
65
66THINKGEAR_SERVER_HOST = configuration.THINKGEAR_SERVER_HOST
67THINKGEAR_SERVER_PORT = configuration.THINKGEAR_SERVER_PORT
68
69THINKGEAR_EEG_POWER_BAND_ORDER = configuration.THINKGEAR_EEG_POWER_BAND_ORDER
70
71THINKGEAR_EMULATION_MAX_ESENSE_VALUE = \
72        configuration.THINKGEAR_EMULATION_MAX_ESENSE_VALUE
73THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE = \
74        configuration.THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
75
76PATH_TO_HCITOOL = '/usr/bin/hcitool'
77
78#UPDATE_INTERFACE_VIA_TIMER = True # Alternative is to establish a
79                                  ## ThinkGear Connect client which
80                                  ## updates the interface on demand
81                                  ## as packets are received
82
83UPDATE_INTERFACE_VIA_TIMER = False
84
85#INTERFACE_UPDATE_FREQUENCY = (1 / 512) * 1000 # ms (512 Hz)
86INTERFACE_UPDATE_FREQUENCY = 1000 # ms
87
88INTERFACE_RAW_EEG_UPDATE_FREQUENCY = 512
89
90### CLASSES ###
91
92class QtUI(QtGui.QWidget, Design):
93       
94        def __init__(self, log, server=None, DEBUG=DEBUG, parent = None):
95               
96                self.log = log
97                self.DEBUG = DEBUG
98                self.parent=parent
99               
100                if self.parent == None:
101                        QtGui.QWidget.__init__(self, parent)
102                        self.setupUi(self)
103               
104                        self.configureSettings()
105                        self.connectWidgets()
106               
107                self.name = "Synapse Interface"
108               
109                self.thinkGearConnectServer = None
110                self.thinkgearConnectClient = None
111               
112                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
113               
114                self.debug_console_buffer = ''
115               
116                self.packets = {}
117                self.packets['rawEeg'] = []
118                self.packets['signals'] = []
119               
120                self.customDataHeaders = []
121               
122                if UPDATE_INTERFACE_VIA_TIMER:
123                        self.updateInterfaceTimer = QtCore.QTimer()
124                        QtCore.QObject.connect(self.updateInterfaceTimer, \
125                                                    QtCore.SIGNAL("timeout()"), \
126                                                    self.updateInterface)
127               
128                if (sys.platform == 'win32'):
129                        self.homepath = os.path.join( \
130                           os.environ['HOMEDRIVE'], \
131                           os.environ['HOMEPATH'], \
132                           'Desktop')
133                else:
134                        self.homepath = os.environ['HOME']
135               
136                if not os.path.exists(self.homepath):
137                        self.homepath = os.getcwd()
138       
139       
140        ##################################################################
141       
142        def configureSettings(self):
143               
144                # Synapse Interface
145                image_path = "puzzlebox.ico"
146                if not os.path.exists(image_path):
147                        image_path = os.path.join(DEFAULT_IMAGE_PATH, image_path)
148               
149                if os.path.exists(image_path):
150                        icon = QtGui.QIcon()
151                        icon.addPixmap(QtGui.QPixmap(image_path), \
152                                            QtGui.QIcon.Normal, \
153                                            QtGui.QIcon.Off)
154                        self.setWindowIcon(icon)
155               
156                image_path = "puzzlebox_logo.png"
157                if not os.path.exists(image_path):
158                        image_path = os.path.join(DEFAULT_IMAGE_PATH, image_path)
159                if os.path.exists(image_path):
160                        self.labelPuzzleboxIcon.setPixmap(QtGui.QPixmap(image_path))
161               
162               
163                if configuration.INTERFACE_TAB_POSITION == 'South':
164                        self.tabWidget.setTabPosition(QtGui.QTabWidget.South)
165                else:
166                        self.tabWidget.setTabPosition(QtGui.QTabWidget.North)
167               
168               
169                # ThinkGear Device
170                self.updateThinkGearDevices()
171               
172               
173                # ThinkGear Connect Server
174                self.textLabelBluetoothStatus.setText("Status: Disconnected")
175               
176                # Display Host for ThinkGear Connect Socket Server
177                self.lineEditThinkGearHost.setText(THINKGEAR_SERVER_HOST)
178               
179                # Display Port for ThinkGear Connect Socket Server
180                self.lineEditThinkGearPort.setText('%i' % THINKGEAR_SERVER_PORT)
181               
182               
183                # ThinkgGear Progress Bars
184                self.progressBarEEGDelta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
185                self.progressBarEEGTheta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
186                self.progressBarEEGLowAlpha.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
187                self.progressBarEEGHighAlpha.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
188                self.progressBarEEGLowBeta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
189                self.progressBarEEGHighBeta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
190                self.progressBarEEGLowGamma.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
191                self.progressBarEEGMidGamma.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
192               
193                self.progressBarAttention.setMaximum(THINKGEAR_EMULATION_MAX_ESENSE_VALUE)
194                self.progressBarMeditation.setMaximum(THINKGEAR_EMULATION_MAX_ESENSE_VALUE)
195               
196                self.progressBarSignalContactQuality.setMaximum(200)
197               
198               
199                if MATPLOTLIB_AVAILABLE:
200                        self.rawEEGMatplot = rawEEGMatplotlibCanvas( \
201                                                self.tabEEGSignals, \
202                                                width=8, \
203                                                height=4, \
204                                                dpi=100, \
205                                                title='Raw EEG Waves')
206                        self.chartEEGMatplot = chartEEGMatplotlibCanvas( \
207                                                self.tabCharts, \
208                                                width=8, \
209                                                height=4, \
210                                                dpi=100, \
211                                                title='EEG Brain Signals')
212               
213                else:
214                        self.tabWidget.removeTab(self.tabWidget.indexOf(self.tabEEGSignals))
215                        self.tabWidget.removeTab(self.tabWidget.indexOf(self.tabCharts))
216       
217       
218        ##################################################################
219       
220        def connectWidgets(self):
221               
222                self.connect(self.pushButtonBluetoothSearch, \
223                                  QtCore.SIGNAL("clicked()"), \
224                                  self.updateThinkGearDevices)
225               
226                self.connect(self.pushButtonBluetoothConnect, \
227                                  QtCore.SIGNAL("clicked()"), \
228                                  self.connectToThinkGearDevice)
229               
230                self.connect(self.pushButtonThinkGearConnect, \
231                                  QtCore.SIGNAL("clicked()"), \
232                                  self.startThinkGearConnectServer)
233               
234                self.connect(self.pushButtonSave, \
235                                  QtCore.SIGNAL("clicked()"), \
236                                  self.saveData)
237               
238                self.connect(self.pushButtonExport, \
239                                  QtCore.SIGNAL("clicked()"), \
240                                  self.exportData)
241               
242                self.connect(self.pushButtonReset, \
243                                  QtCore.SIGNAL("clicked()"), \
244                                  self.resetData)
245       
246       
247        ##################################################################
248       
249        def connectToThinkGearDevice(self):
250               
251                device_selection = self.comboBoxDeviceSelect.currentText()
252               
253                self.disconnect(self.pushButtonBluetoothConnect, \
254                                     QtCore.SIGNAL("clicked()"), \
255                                     self.connectToThinkGearDevice)
256               
257                self.connect(self.pushButtonBluetoothConnect, \
258                                  QtCore.SIGNAL("clicked()"), \
259                                  self.disconnectFromThinkGearDevice)
260               
261                self.textLabelBluetoothStatus.setText("Status: Connected")
262               
263                self.pushButtonBluetoothSearch.setEnabled(False)
264               
265                self.pushButtonBluetoothConnect.setText('Disconnect')
266                self.pushButtonBluetoothConnect.setChecked(True)
267               
268                self.comboBoxDeviceSelect.setEnabled(False)
269       
270       
271        ##################################################################
272       
273        def disconnectFromThinkGearDevice(self):
274               
275                self.disconnect(self.pushButtonBluetoothConnect, \
276                                     QtCore.SIGNAL("clicked()"), \
277                                     self.disconnectFromThinkGearDevice)
278               
279                self.connect(self.pushButtonBluetoothConnect, \
280                                  QtCore.SIGNAL("clicked()"), \
281                                  self.connectToThinkGearDevice)
282               
283                self.textLabelBluetoothStatus.setText("Status: Disconnected")
284               
285                self.pushButtonBluetoothSearch.setEnabled(True)
286               
287                self.pushButtonBluetoothConnect.setText('Connect')
288                self.pushButtonBluetoothConnect.setChecked(False)
289               
290                self.comboBoxDeviceSelect.setEnabled(True)
291               
292               
293                self.progressBarEEGDelta.setValue(0)
294                self.progressBarEEGTheta.setValue(0)
295                self.progressBarEEGLowAlpha.setValue(0)
296                self.progressBarEEGHighAlpha.setValue(0)
297                self.progressBarEEGLowBeta.setValue(0)
298                self.progressBarEEGHighBeta.setValue(0)
299                self.progressBarEEGLowGamma.setValue(0)
300                self.progressBarEEGMidGamma.setValue(0)
301               
302                self.progressBarAttention.setValue(0)
303                self.progressBarMeditation.setValue(0)
304               
305                self.progressBarSignalContactQuality.setValue(0)
306               
307                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
308               
309                # In case the user connects to a MindSet, then disconnects
310                # and re-connects to a MindSet Emulator,
311                # we need to reset the max power values
312                self.progressBarEEGDelta.setMaximum(self.maxEEGPower)
313                self.progressBarEEGTheta.setMaximum(self.maxEEGPower)
314                self.progressBarEEGLowAlpha.setMaximum(self.maxEEGPower)
315                self.progressBarEEGHighAlpha.setMaximum(self.maxEEGPower)
316                self.progressBarEEGLowBeta.setMaximum(self.maxEEGPower)
317                self.progressBarEEGHighBeta.setMaximum(self.maxEEGPower)
318                self.progressBarEEGLowGamma.setMaximum(self.maxEEGPower)
319                self.progressBarEEGMidGamma.setMaximum(self.maxEEGPower)
320       
321       
322        ##################################################################
323       
324        def startThinkGearConnectServer(self):
325               
326                # Ensure EEG device is connected first
327               
328                if not self.pushButtonBluetoothConnect.isChecked():
329                        self.connectToThinkGearDevice()
330               
331               
332                self.pushButtonBluetoothSearch.setEnabled(False)
333                self.pushButtonBluetoothConnect.setEnabled(False)
334               
335                server_interface = str(self.lineEditThinkGearHost.text())
336                server_port = int(self.lineEditThinkGearPort.text())
337                device_address = str(self.comboBoxDeviceSelect.currentText())
338                emulate_headset_data = (device_address == 'ThinkGear Emulator')
339               
340               
341                self.thinkGearConnectServer = \
342                        synapse_server.ThinkgearServer( \
343                                self.log, \
344                                server_interface=server_interface, \
345                                server_port=server_port, \
346                                device_address=device_address, \
347                                emulate_headset_data=emulate_headset_data, \
348                                DEBUG=DEBUG, \
349                                parent=self)
350               
351                self.thinkGearConnectServer.start()
352               
353               
354                if UPDATE_INTERFACE_VIA_TIMER:
355                        self.updateInterfaceTimer.start(INTERFACE_UPDATE_FREQUENCY)
356               
357                else:
358                        self.thinkgearConnectClient = \
359                                thinkgear_client.QtClient( \
360                                        self.log, \
361                                        server_host=server_interface, \
362                                        server_port=server_port, \
363                                        DEBUG=0, \
364                                        parent=self)
365                       
366                        self.thinkgearConnectClient.start()
367               
368               
369                self.disconnect(self.pushButtonThinkGearConnect, \
370                                     QtCore.SIGNAL("clicked()"), \
371                                     self.startThinkGearConnectServer)
372               
373                self.connect(self.pushButtonThinkGearConnect, \
374                                  QtCore.SIGNAL("clicked()"), \
375                                  self.stopThinkGearConnectServer)
376               
377                self.lineEditThinkGearHost.setEnabled(False)
378                self.lineEditThinkGearPort.setEnabled(False)
379               
380                self.pushButtonThinkGearConnect.setText('Stop')
381       
382       
383        ##################################################################
384       
385        def stopThinkGearConnectServer(self):
386               
387                if UPDATE_INTERFACE_VIA_TIMER:
388                        self.updateInterfaceTimer.stop()
389                else:
390                        try:
391                                self.thinkgearConnectClient.disconnectFromHost()
392                        except Exception, e:
393                                if self.DEBUG:
394                                        print "Call failed to self.thinkgearConnectClient.disconnectFromHost():",
395                                        print e
396                       
397                        try:
398                                self.thinkGearConnectServer.exitThread()
399                        except Exception, e:
400                                if self.DEBUG:
401                                        print "Call failed to self.thinkGearConnectServer.exitThread():",
402                                        print e
403               
404                self.disconnect(self.pushButtonThinkGearConnect, \
405                                QtCore.SIGNAL("clicked()"), \
406                                self.stopThinkGearConnectServer)
407               
408                self.connect(self.pushButtonThinkGearConnect, \
409                                  QtCore.SIGNAL("clicked()"), \
410                                  self.startThinkGearConnectServer)
411               
412                self.lineEditThinkGearHost.setEnabled(True)
413                self.lineEditThinkGearPort.setEnabled(True)
414               
415                self.pushButtonThinkGearConnect.setText('Start')
416               
417                #self.pushButtonBluetoothSearch.setEnabled(True)
418                self.pushButtonBluetoothConnect.setEnabled(True)
419               
420                self.pushButtonThinkGearConnect.setChecked(False)
421       
422       
423        ##################################################################
424       
425        def updateInterface(self):
426               
427                if not self.thinkGearConnectServer.emulate_headset_data:
428                        self.processPacketThinkGear( \
429                                self.thinkGearConnectServer.protocol.data_packet)
430       
431       
432        ##################################################################
433       
434        def parseTimeStamp(self, timestamp, local_version=False):
435               
436                try:
437                        decimal = '%f' % timestamp
438                        decimal = decimal.split('.')[1]
439                except:
440                        decimal = '0'
441               
442                localtime = time.localtime(timestamp)
443               
444                if local_version:
445                        date = time.strftime('%x', localtime)
446                        localtime = time.strftime('%X', localtime)
447               
448                else:
449                        date = time.strftime('%Y-%m-%d', localtime)
450                        localtime = time.strftime('%H:%M:%S', localtime)
451                        localtime = '%s.%s %s' % (localtime, decimal, \
452                                       time.strftime('%Z', time.localtime(timestamp)))
453               
454               
455                return(date, localtime)
456       
457       
458        ##################################################################
459       
460        def processPacketThinkGear(self, packet):
461               
462                if self.DEBUG > 2:
463                        print packet
464               
465               
466                if ('rawEeg' in packet.keys()):
467                        self.packets['rawEeg'].append(packet['rawEeg'])
468                        value = packet['rawEeg']
469                        if MATPLOTLIB_AVAILABLE and \
470                                (self.tabWidget.currentIndex() == \
471                                 self.tabWidget.indexOf(self.tabEEGSignals)):
472                                self.rawEEGMatplot.update_figure(value)
473                else:
474                        self.packets['signals'].append(packet)
475               
476               
477                if ('poorSignalLevel' in packet.keys()):
478                        value = 200 - packet['poorSignalLevel']
479                        self.progressBarSignalContactQuality.setValue(value)
480                        self.textEditDebugConsole.append("")
481                        try:
482                                (date, localtime) = self.parseTimeStamp(packet['timestamp'])
483                                self.textEditDebugConsole.append("Timestamp: %s %s" % (date, localtime))
484                        except:
485                                pass
486                        self.textEditDebugConsole.append("poorSignalLevel: %i" % \
487                                                         packet['poorSignalLevel'])
488               
489               
490                if ('eSense' in packet.keys()):
491                       
492                        if ('attention' in packet['eSense'].keys()):
493                                value = packet['eSense']['attention']
494                                self.progressBarAttention.setValue(value)
495                                self.textEditDebugConsole.append("eSense attention: %i" % value)
496                       
497                        if ('meditation' in packet['eSense'].keys()):
498                                value = packet['eSense']['meditation']
499                                self.progressBarMeditation.setValue(value)
500                                self.textEditDebugConsole.append("eSense meditation: %i" % value)
501                       
502                       
503                        if MATPLOTLIB_AVAILABLE:
504                                self.chartEEGMatplot.update_values('eSense', packet['eSense'])
505                                if (self.tabWidget.currentIndex() == \
506                                    self.tabWidget.indexOf(self.tabCharts)):
507                                        self.chartEEGMatplot.update_figure('eSense', packet['eSense'])
508               
509               
510                if ('eegPower' in packet.keys()):
511                       
512                        # If we are not emulating packets we'll set the maximum EEG Power value
513                        # threshold to the default (or maximum value found within this packet)
514                        if not self.thinkGearConnectServer.emulate_headset_data:
515                                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
516                       
517                        for value in packet['eegPower'].keys():
518                                if packet['eegPower'][value] > self.maxEEGPower:
519                                        self.maxEEGPower = packet['eegPower'][value]
520                       
521                       
522                        if ('delta' in packet['eegPower'].keys()):
523                                value = packet['eegPower']['delta']
524                                self.progressBarEEGDelta.setMaximum(self.maxEEGPower)
525                                self.progressBarEEGDelta.setValue(value)
526                                self.textEditDebugConsole.append("delta: %i" % value)
527                       
528                        if ('theta' in packet['eegPower'].keys()):
529                                value = packet['eegPower']['theta']
530                                self.progressBarEEGTheta.setMaximum(self.maxEEGPower)
531                                self.progressBarEEGTheta.setValue(value)
532                                self.textEditDebugConsole.append("theta: %i" % value)
533                       
534                        if ('lowAlpha' in packet['eegPower'].keys()):
535                                value = packet['eegPower']['lowAlpha']
536                                self.progressBarEEGLowAlpha.setMaximum(self.maxEEGPower)
537                                self.progressBarEEGLowAlpha.setValue(value)
538                                self.textEditDebugConsole.append("lowAlpha: %i" % value)
539                       
540                        if ('highAlpha' in packet['eegPower'].keys()):
541                                value = packet['eegPower']['highAlpha']
542                                self.progressBarEEGHighAlpha.setMaximum(self.maxEEGPower)
543                                self.progressBarEEGHighAlpha.setValue(value)
544                                self.textEditDebugConsole.append("highAlpha: %i" % value)
545                       
546                        if ('lowBeta' in packet['eegPower'].keys()):
547                                value = packet['eegPower']['lowBeta']
548                                self.progressBarEEGLowBeta.setMaximum(self.maxEEGPower)
549                                self.progressBarEEGLowBeta.setValue(value)
550                                self.textEditDebugConsole.append("lowBeta: %i" % value)
551                       
552                        if ('highBeta' in packet['eegPower'].keys()):
553                                value = packet['eegPower']['highBeta']
554                                self.progressBarEEGHighBeta.setMaximum(self.maxEEGPower)
555                                self.progressBarEEGHighBeta.setValue(value)
556                                self.textEditDebugConsole.append("highBeta: %i" % value)
557                       
558                        if ('lowGamma' in packet['eegPower'].keys()):
559                                value = packet['eegPower']['lowGamma']
560                                self.progressBarEEGLowGamma.setMaximum(self.maxEEGPower)
561                                self.progressBarEEGLowGamma.setValue(value)
562                                self.textEditDebugConsole.append("lowGamma: %i" % value)
563                       
564                        if ('highGamma' in packet['eegPower'].keys()):
565                                value = packet['eegPower']['highGamma']
566                                self.progressBarEEGMidGamma.setMaximum(self.maxEEGPower)
567                                self.progressBarEEGMidGamma.setValue(value)
568                                self.textEditDebugConsole.append("highGamma: %i" % value)
569                       
570                       
571                        if MATPLOTLIB_AVAILABLE:
572                                self.chartEEGMatplot.update_values('eegPower', packet['eegPower'])
573                                if (self.tabWidget.currentIndex() == \
574                                    self.tabWidget.indexOf(self.tabCharts)):
575                                        self.chartEEGMatplot.update_figure('eegPower', packet['eegPower'])
576               
577               
578                if ((self.thinkGearConnectServer.protocol != None) and
579                    (self.tabWidget.currentIndex() == \
580                     self.tabWidget.indexOf(self.tabControlPanel))):
581                       
582                        self.updateProfileSessionStatus()
583       
584       
585        ##################################################################
586       
587        def updateProfileSessionStatus(self):
588               
589                session_time = self.calculateSessionTime()
590               
591                if self.parent == None:
592                        target = self
593                else:
594                        target = self.parent
595               
596                target.textLabelSessionTime.setText(session_time)
597               
598                target.textLabelPacketsReceived.setText( "%i" % \
599                        target.thinkGearConnectServer.protocol.packet_count)
600                target.textLabelPacketsDropped.setText( "%i" % \
601                        target.thinkGearConnectServer.protocol.bad_packets)
602       
603       
604        ##################################################################
605       
606        def calculateSessionTime(self):
607               
608                if self.parent == None:
609                        server = self.thinkGearConnectServer
610                else:
611                        server = self.parent.thinkGearConnectServer
612               
613                session_time = time.time() - \
614                        server.protocol.session_start_timestamp
615               
616                session_time = int(session_time)
617               
618                session_time = self.convert_seconds_to_datetime(session_time)
619               
620                return(session_time)
621       
622       
623        ##################################################################
624       
625        def enumerateSerialPorts(self):
626               
627                """ Uses the Win32 registry to return an
628                iterator of serial (COM) ports
629                existing on this computer.
630               
631                from http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
632                """
633         
634                path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
635                try:
636                        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
637                except WindowsError:
638                        #raise IterationError
639                        return
640               
641                for i in itertools.count():
642                        try:
643                                val = winreg.EnumValue(key, i)
644                                yield str(val[1])
645                        except EnvironmentError:
646                                break
647       
648       
649        ##################################################################
650       
651        def fullPortName(self, portname):
652               
653                """ Given a port-name (of the form COM7,
654                COM12, CNCA0, etc.) returns a full
655                name suitable for opening with the
656                Serial class.
657                """
658               
659                m = re.match('^COM(\d+)$', portname)
660                if m and int(m.group(1)) < 10:
661                        return portname
662               
663                return '\\\\.\\' + portname
664       
665       
666        ##################################################################
667       
668        def searchForThinkGearDevices(self):
669               
670                thinkgear_devices = []
671               
672                #self.pushButtonBluetoothSearch.setText('Searching')
673               
674                if (sys.platform == 'win32'):
675                       
676                        # Bluetooth module doesn't compile properly under WindowsError
677                       
678                        for portname in self.enumerateSerialPorts():
679                               
680                                if portname not in thinkgear_devices:
681                                        #portname = self.fullPortName(portname)
682                                        thinkgear_devices.append(portname)
683               
684               
685                else:
686                       
687                        bluetooth_devices = []
688                       
689                        try:
690                                bluetooth_devices = bluetooth.discover_devices( \
691                                                       duration=5, \
692                                                       flush_cache=True, \
693                                                       lookup_names=False)
694                        except:
695                                #command = '%s con' % PATH_TO_HCITOOL
696                                command = '%s scan' % PATH_TO_HCITOOL
697                               
698                                if self.DEBUG:
699                                        print 'Calling "%s":' % command
700                               
701                                output = os.popen(command, 'r')
702                               
703                                for line in output.readlines():
704                                        print line
705                                        try:
706                                                address = line.split(' ')[2]
707                                        except:
708                                                pass
709                                        else:
710                                                bluetooth_devices.append(address)
711                       
712                       
713                        for address in bluetooth_devices:
714                                device_name = bluetooth.lookup_name(address)
715                                if ((device_name == 'MindSet') and \
716                                    (address not in thinkgear_devices)):
717                                        thinkgear_devices.append(address)
718                       
719                       
720                        if self.DEBUG > 2:
721                                print "Bluetooth MindSet devices found:",
722                                print thinkgear_devices
723                       
724                       
725                        if self.parent == None:
726                                self.comboBoxDeviceSelect.clear()
727                        else:
728                                self.parent.comboBoxDeviceSelect.clear()
729                       
730                        #self.comboBoxDeviceSelect.addItem('ThinkGear Emulator')
731                       
732                        if os.path.exists('/dev/ttyUSB0'):
733                                thinkgear_devices.append('/dev/ttyUSB0')
734                        if os.path.exists('/dev/ttyUSB1'):
735                                thinkgear_devices.append('/dev/ttyUSB1')
736                        if os.path.exists('/dev/ttyUSB2'):
737                                thinkgear_devices.append('/dev/ttyUSB2')
738                        if os.path.exists('/dev/ttyUSB3'):
739                                thinkgear_devices.append('/dev/ttyUSB3')
740                        if os.path.exists('/dev/ttyUSB4'):
741                                thinkgear_devices.append('/dev/ttyUSB4')
742                        if os.path.exists('/dev/ttyUSB5'):
743                                thinkgear_devices.append('/dev/ttyUSB5')
744                        if os.path.exists('/dev/ttyUSB6'):
745                                thinkgear_devices.append('/dev/ttyUSB6')
746                        if os.path.exists('/dev/ttyUSB7'):
747                                thinkgear_devices.append('/dev/ttyUSB7')
748                        if os.path.exists('/dev/ttyUSB8'):
749                                thinkgear_devices.append('/dev/ttyUSB8')
750                        if os.path.exists('/dev/ttyUSB9'):
751                                thinkgear_devices.append('/dev/ttyUSB9')
752               
753                        if os.path.exists('/dev/ttyACM0'):
754                                thinkgear_devices.append('/dev/ttyACM0')
755                        if os.path.exists('/dev/ttyACM1'):
756                                thinkgear_devices.append('/dev/ttyACM1')
757                        if os.path.exists('/dev/ttyACM2'):
758                                thinkgear_devices.append('/dev/ttyACM2')
759                        if os.path.exists('/dev/ttyACM3'):
760                                thinkgear_devices.append('/dev/ttyACM3')
761                        if os.path.exists('/dev/ttyACM4'):
762                                thinkgear_devices.append('/dev/ttyACM4')
763               
764                if self.DEBUG:
765                        print "ThinkGear devices found:",
766                        print thinkgear_devices
767               
768               
769                return(thinkgear_devices)
770       
771       
772        ##################################################################
773       
774        def updateThinkGearDevices(self):
775               
776                devices = self.searchForThinkGearDevices()
777               
778                devices.insert(0, 'ThinkGear Emulator')
779               
780                for device in devices:
781                        self.comboBoxDeviceSelect.addItem(device)
782       
783       
784        ##################################################################
785       
786        def collectData(self):
787               
788                if self == None:
789                        target = self
790                else:
791                        target = self.parent
792               
793                data = {}
794               
795                data['rawEeg'] = target.packets['rawEeg']
796                data['signals'] = target.packets['signals']
797               
798                data['sessionTime'] = self.calculateSessionTime()
799               
800                data['profileName'] = str(target.lineEditSessionProfile.text())
801               
802                return(data)
803       
804       
805        ##################################################################
806       
807        def saveData(self):
808               
809                if self == None:
810                        target = self
811                else:
812                        target = self.parent
813               
814                data = self.collectData()
815               
816                (date, localtime) = self.parseTimeStamp(time.time())
817               
818                default_filename = '%s %s.synapse' % (date, \
819                                      target.lineEditSessionProfile.text())
820                                     
821                default_filename = os.path.join(self.homepath, default_filename)
822               
823                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
824                                 caption="Save Session Data to File", \
825                                 dir=default_filename, \
826                                 filter="Puzzlebox Synapse Data File (*.synapse)")
827               
828                try:
829                        output_file = output_file[0]
830                except:
831                        pass
832               
833                file = open(str(output_file), 'w')
834                pickle.dump(data, file)
835                file.close()
836       
837       
838        ##################################################################
839       
840        def exportData(self):
841               
842                if self == None:
843                        target = self
844                else:
845                        target = self.parent
846               
847                (date, localtime) = self.parseTimeStamp(time.time())
848               
849                default_filename = '%s %s.csv' % (date, \
850                                      target.lineEditSessionProfile.text())
851               
852                default_filename = os.path.join(self.homepath, default_filename)
853               
854                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
855                                 caption="Export Session Data to File", \
856                                 dir=default_filename, \
857                                 filter="CSV File (*.csv);;Text File (*.txt)")
858               
859                try:
860                        output_file = output_file[0]
861                except:
862                        pass
863               
864                if str(output_file).endswith('.csv'):
865                       
866                        outputData = self.exportDataToCSV()
867               
868               
869                else:
870                       
871                        try:
872                                outputData = self.textEditDebugConsole.toPlainText()
873                        except:
874                                outputData = self.exportDataToCSV()
875                       
876                       
877                file = open(str(output_file), 'w')
878                file.write(outputData)
879                file.close()
880       
881       
882        ##################################################################
883       
884        def exportDataToCSV(self):
885               
886                if self == None:
887                        target = self
888                else:
889                        target = self.parent
890               
891                header = 'Date,Time,Delta,Theta,Low Alpha,High Alpha,Low Beta,High Beta,Low Gamma,Mid Gamma,Attention,Meditation,Signal Level'
892               
893                for each in target.customDataHeaders:
894                        header = header + ',%s' % each
895               
896                header = header + '\n'
897               
898                csv = {}
899               
900                for packet in target.packets['signals']:
901                       
902                        if 'rawEeg' in packet.keys():
903                                continue
904                       
905                        if packet['timestamp'] not in csv.keys():
906                               
907                                #print packet
908                                timestamp = packet['timestamp']
909                                (date, localtime) = self.parseTimeStamp(timestamp)
910                               
911                                csv[timestamp] = {}
912                                csv[timestamp]['Date'] = date
913                                csv[timestamp]['Time'] = localtime
914                                csv[timestamp]['Delta'] = ''
915                                csv[timestamp]['Theta'] = ''
916                                csv[timestamp]['Low Alpha'] = ''
917                                csv[timestamp]['High Alpha'] = ''
918                                csv[timestamp]['Low Beta'] = ''
919                                csv[timestamp]['High Beta'] = ''
920                                csv[timestamp]['Low Gamma'] = ''
921                                csv[timestamp]['Mid Gamma'] = ''
922                                csv[timestamp]['Attention'] = ''
923                                csv[timestamp]['Meditation'] = ''
924                                csv[timestamp]['Signal Level'] = ''
925                       
926                       
927                        if 'eSense' in packet.keys():
928                                if 'attention' in packet['eSense'].keys():
929                                        csv[timestamp]['Attention'] = packet['eSense']['attention']
930                                if 'meditation' in packet['eSense'].keys():
931                                        csv[timestamp]['Meditation'] = packet['eSense']['meditation']
932                       
933                        if 'eegPower' in packet.keys():
934                                if 'delta' in packet['eegPower'].keys():
935                                        csv[timestamp]['Delta'] = packet['eegPower']['delta']
936                                if 'theta' in packet['eegPower'].keys():
937                                        csv[timestamp]['Theta'] = packet['eegPower']['theta']
938                                if 'lowAlpha' in packet['eegPower'].keys():
939                                        csv[timestamp]['Low Alpha'] = packet['eegPower']['lowAlpha']
940                                if 'highAlpha' in packet['eegPower'].keys():
941                                        csv[timestamp]['High Alpha'] = packet['eegPower']['highAlpha']
942                                if 'lowBeta' in packet['eegPower'].keys():
943                                        csv[timestamp]['Low Beta'] = packet['eegPower']['lowBeta']
944                                if 'highBeta' in packet['eegPower'].keys():
945                                        csv[timestamp]['High Beta'] = packet['eegPower']['highBeta']
946                                if 'lowGamma' in packet['eegPower'].keys():
947                                        csv[timestamp]['Low Gamma'] = packet['eegPower']['lowGamma']
948                                if 'highGamma' in packet['eegPower'].keys():
949                                        csv[timestamp]['Mid Gamma'] = packet['eegPower']['highGamma']
950                       
951                        if 'poorSignalLevel' in packet.keys():
952                                csv[timestamp]['Signal Level'] = packet['poorSignalLevel']
953               
954               
955                output = header
956               
957                csv_keys = csv.keys()
958                csv_keys.sort()
959               
960                for key in csv_keys:
961                       
962                        row = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n' % \
963                              (csv[key]['Date'], \
964                               csv[key]['Time'], \
965                               csv[key]['Delta'], \
966                               csv[key]['Theta'], \
967                               csv[key]['Low Alpha'], \
968                               csv[key]['High Alpha'], \
969                               csv[key]['Low Beta'], \
970                               csv[key]['High Beta'], \
971                               csv[key]['Low Gamma'], \
972                               csv[key]['Mid Gamma'], \
973                               csv[key]['Attention'], \
974                               csv[key]['Meditation'], \
975                               csv[key]['Signal Level'])
976                       
977                       
978                        output = output + row
979               
980               
981                return(output)
982       
983       
984        ##################################################################
985       
986        def resetData(self):
987               
988                if self == None:
989                        target = self
990                else:
991                        target = self.parent
992               
993                target.packets['rawEeg'] = []
994                target.packets['signals'] = []
995               
996                target.thinkGearConnectServer.protocol.session_start_timestamp = \
997                        time.time()
998               
999                target.thinkGearConnectServer.protocol.packet_count = 0
1000                target.thinkGearConnectServer.protocol.bad_packets = 0
1001               
1002                self.updateProfileSessionStatus()
1003               
1004                try:
1005                        target.textEditDebugConsole.setText("")
1006                except:
1007                        pass
1008       
1009       
1010        #####################################################################
1011       
1012        def convert_seconds_to_datetime(self, duration):
1013               
1014                duration_hours = duration / (60 * 60)
1015                duration_minutes = (duration - (duration_hours * (60 * 60))) / 60
1016                duration_seconds = (duration - (duration_hours * (60 * 60)) - (duration_minutes * 60))
1017               
1018                duration_hours = '%i' % duration_hours
1019                if (len(duration_hours) == 1):
1020                        duration_hours = "0%s" % duration_hours
1021               
1022                duration_minutes = '%i' % duration_minutes
1023                if (len(duration_minutes) == 1):
1024                        duration_minutes = "0%s" % duration_minutes
1025               
1026                duration_seconds = '%i' % duration_seconds
1027                if (len(duration_seconds) == 1):
1028                        duration_seconds = "0%s" % duration_seconds
1029               
1030                datetime = '%s:%s:%s' % (duration_hours, duration_minutes, duration_seconds)
1031               
1032                return(datetime)
1033       
1034       
1035        ##################################################################
1036       
1037        def closeEvent(self, event):
1038               
1039                quit_message = "Are you sure you want to exit the program?"
1040               
1041                reply = QtGui.QMessageBox.question( \
1042                           self, \
1043                          'Message', \
1044                           quit_message, \
1045                           QtGui.QMessageBox.Yes, \
1046                           QtGui.QMessageBox.No)
1047               
1048                if reply == QtGui.QMessageBox.Yes:
1049                       
1050                        if UPDATE_INTERFACE_VIA_TIMER:
1051                                self.updateInterfaceTimer.stop()
1052                        else:
1053                                if self.thinkgearConnectClient != None:
1054                                        self.thinkgearConnectClient.disconnectFromHost()
1055                       
1056                        if self.thinkGearConnectServer != None:
1057                                self.thinkGearConnectServer.exitThread()
1058                       
1059                        event.accept()
1060               
1061                else:
1062                        event.ignore()
Note: See TracBrowser for help on using the repository browser.