source: trunk/synapse/Puzzlebox/Synapse/Interface.py @ 259

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

trunk/synapse/Puzzlebox/Synapse/Interface.py:

  • Now supports configurable interface tab positioning

trunk/synapse/Puzzlebox/Synapse/Configuration.py:

  • Now supports configurable interface tab positioning

trunk/synapse/puzzlebox_synapse_configuration.ini:

  • Now supports configurable interface tab positioning

trunk/brainstorms/Puzzlebox/Brainstorms/Interface.py:

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