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

Last change on this file since 368 was 368, checked in by sc, 10 years ago
  • Support for Emotiv EPOC added to Puzzlebox Synapse
  • Support for emulating ThinkGear? Connect packets using data from Emotiv
  • Property svn:executable set to *
File size: 50.8 KB
Line 
1# -*- coding: utf-8 -*-
2
3# Copyright Puzzlebox Productions, LLC (2010-2012)
4#
5# This code is released under the GNU Pulic License (GPL) version 2
6# For more information please refer to http://www.gnu.org/copyleft/gpl.html
7
8__changelog__ = """\
9Last Update: 2012.03.30
10"""
11
12__todo__ = """
13- update configuration.ini file with settings entered into interface
14"""
15
16### IMPORTS ###
17import os, sys, time
18
19import Puzzlebox.Synapse.Configuration as configuration
20
21if configuration.ENABLE_PYSIDE:
22        try:
23                import PySide as PyQt4
24                from PySide import QtCore, QtGui, QtNetwork
25        except Exception, e:
26                print "ERROR: Exception importing PySide:",
27                print e
28                configuration.ENABLE_PYSIDE = False
29        else:
30                print "INFO: [Synapse:Interface] Using PySide module"
31
32if not configuration.ENABLE_PYSIDE:
33        print "INFO: [Synapse:Interface] Using PyQt4 module"
34        from PyQt4 import QtCore, QtGui, QtNetwork
35
36
37try:
38        from Interface_Plot import *
39        MATPLOTLIB_AVAILABLE = True
40except Exception, e:
41        print "ERROR: Exception importing Interface_Plot:",
42        print e
43        MATPLOTLIB_AVAILABLE = False
44
45
46if (sys.platform == 'win32'):
47        import _winreg as winreg
48        import itertools
49        import re
50        import serial
51        DEFAULT_IMAGE_PATH = 'images'
52elif (sys.platform == 'darwin'):
53        DEFAULT_IMAGE_PATH = 'images'
54else:
55        import bluetooth
56        DEFAULT_IMAGE_PATH = '/usr/share/puzzlebox_synapse/images'
57
58
59try:
60        import cPickle as pickle
61except:
62        import pickle
63
64from Interface_Design import Ui_Form as Design
65
66import Puzzlebox.Synapse.Client as synapse_client
67import Puzzlebox.Synapse.ThinkGear.Server as thinkgear_server
68import Puzzlebox.Synapse.Emotiv.Server as emotiv_server
69#import Puzzlebox.Synapse.Emotiv.Client as emotiv_client
70#import puzzlebox_logger
71
72
73#####################################################################
74# Globals
75#####################################################################
76
77DEBUG = configuration.DEBUG
78
79SYNAPSE_SERVER_HOST = configuration.SYNAPSE_SERVER_HOST
80SYNAPSE_SERVER_PORT = configuration.SYNAPSE_SERVER_PORT
81
82EMULATE_THINKGEAR_FOR_EMOTIV = configuration.EMULATE_THINKGEAR_FOR_EMOTIV
83
84#THINKGEAR_EEG_POWER_BAND_ORDER = configuration.THINKGEAR_EEG_POWER_BAND_ORDER
85
86THINKGEAR_EMULATION_MAX_ESENSE_VALUE = \
87        configuration.THINKGEAR_EMULATION_MAX_ESENSE_VALUE
88THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE = \
89        configuration.THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
90
91PATH_TO_HCITOOL = '/usr/bin/hcitool'
92
93#UPDATE_INTERFACE_VIA_TIMER = True # Alternative is to establish a
94                                  ## ThinkGear Connect client which
95                                  ## updates the interface on demand
96                                  ## as packets are received
97
98UPDATE_INTERFACE_VIA_TIMER = False
99
100#INTERFACE_UPDATE_FREQUENCY = (1 / 512) * 1000 # ms (512 Hz)
101INTERFACE_UPDATE_FREQUENCY = 1000 # ms
102
103INTERFACE_RAW_EEG_UPDATE_FREQUENCY = 512
104
105PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD = 0.75
106
107
108#####################################################################
109# Classes
110#####################################################################
111
112class puzzlebox_synapse_interface(QtGui.QWidget, Design):
113       
114        def __init__(self, log, \
115                     server=None, \
116                     DEBUG=DEBUG, \
117                     parent=None, \
118                     embedded_mode=False):
119               
120                self.log = log
121                self.DEBUG = DEBUG
122                self.parent=parent
123                self.embedded_mode=embedded_mode
124               
125                if self.parent == None:
126                        QtGui.QWidget.__init__(self, parent)
127                        self.setupUi(self)
128               
129                        self.configureSettings()
130                        self.connectWidgets()
131               
132                self.name = "Synapse Interface"
133               
134                self.synapseServer = None
135                self.synapseClient = None
136                #self.thinkgearConnectClient = None
137                #self.emotivClient = None
138               
139                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
140               
141                self.debug_console_buffer = ''
142               
143                self.packets = {}
144                self.packets['rawEeg'] = []
145                self.packets['signals'] = []
146               
147                self.customDataHeaders = []
148               
149                if UPDATE_INTERFACE_VIA_TIMER:
150                        self.updateInterfaceTimer = QtCore.QTimer()
151                        QtCore.QObject.connect(self.updateInterfaceTimer, \
152                                                    QtCore.SIGNAL("timeout()"), \
153                                                    self.updateInterface)
154               
155               
156                if (sys.platform == 'win32'):
157                        self.homepath = os.path.join( \
158                           os.environ['HOMEDRIVE'], \
159                           os.environ['HOMEPATH'], \
160                           'Desktop')
161                elif (sys.platform == 'darwin'):
162                        desktop = os.path.join(os.environ['HOME'], 'Documents')
163                        if os.path.exists(desktop):
164                                self.homepath = desktop
165                        else:
166                                self.homepath = os.environ['HOME']
167                else:
168                        desktop = os.path.join(os.environ['HOME'], 'Desktop')
169                        if os.path.exists(desktop):
170                                self.homepath = desktop
171                        else:
172                                self.homepath = os.environ['HOME']
173               
174               
175                if not os.path.exists(self.homepath):
176                        if self.DEBUG:
177                                print "DEBUG: User default path not found"
178                        self.homepath = os.getcwd()
179               
180               
181                self.activePlugins = []
182       
183       
184        ##################################################################
185       
186        def configureSettings(self):
187               
188                # Synapse Interface
189                image_path = "puzzlebox.ico"
190                if not os.path.exists(image_path):
191                        image_path = os.path.join(DEFAULT_IMAGE_PATH, image_path)
192               
193                if os.path.exists(image_path):
194                        icon = QtGui.QIcon()
195                        icon.addPixmap(QtGui.QPixmap(image_path), \
196                                            QtGui.QIcon.Normal, \
197                                            QtGui.QIcon.Off)
198                        self.setWindowIcon(icon)
199               
200                image_path = "puzzlebox_logo.png"
201                if not os.path.exists(image_path):
202                        image_path = os.path.join(DEFAULT_IMAGE_PATH, image_path)
203                if os.path.exists(image_path):
204                        self.labelPuzzleboxIcon.setPixmap(QtGui.QPixmap(image_path))
205               
206               
207                if configuration.INTERFACE_TAB_POSITION == 'South':
208                        self.tabWidget.setTabPosition(QtGui.QTabWidget.South)
209                else:
210                        self.tabWidget.setTabPosition(QtGui.QTabWidget.North)
211               
212               
213                # EEG Devices
214                self.updateDevices()
215               
216               
217                # Connect Server
218                self.textLabelBluetoothStatus.setText("Status: Disconnected")
219               
220                # Display Host for ThinkGear Connect Socket Server
221                self.lineEditSynapseHost.setText(SYNAPSE_SERVER_HOST)
222               
223                # Display Port for ThinkGear Connect Socket Server
224                self.lineEditSynapsePort.setText('%i' % SYNAPSE_SERVER_PORT)
225               
226               
227                # ThinkgGear Progress Bars
228                self.progressBarEEGDelta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
229                self.progressBarEEGTheta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
230                self.progressBarEEGLowAlpha.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
231                self.progressBarEEGHighAlpha.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
232                self.progressBarEEGLowBeta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
233                self.progressBarEEGHighBeta.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
234                self.progressBarEEGLowGamma.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
235                self.progressBarEEGMidGamma.setMaximum(THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE)
236               
237                self.progressBarAttention.setMaximum(THINKGEAR_EMULATION_MAX_ESENSE_VALUE)
238                self.progressBarMeditation.setMaximum(THINKGEAR_EMULATION_MAX_ESENSE_VALUE)
239               
240                self.progressBarSignalContactQuality.setMaximum(200)
241               
242               
243                if MATPLOTLIB_AVAILABLE:
244                        self.rawEEGMatplot = rawEEGMatplotlibCanvas( \
245                                                self.tabEEGSignals, \
246                                                width=8, \
247                                                height=4, \
248                                                dpi=100, \
249                                                title='Raw EEG Waves')
250                        self.chartEEGMatplot = chartEEGMatplotlibCanvas( \
251                                                self.tabCharts, \
252                                                width=8, \
253                                                height=4, \
254                                                dpi=100, \
255                                                title='EEG Brain Signals')
256               
257                else:
258                        self.tabWidget.removeTab(self.tabWidget.indexOf(self.tabEEGSignals))
259                        self.tabWidget.removeTab(self.tabWidget.indexOf(self.tabCharts))
260       
261       
262        ##################################################################
263       
264        def connectWidgets(self):
265               
266                self.connect(self.comboBoxEEGHeadsetModel, \
267                             QtCore.SIGNAL("currentIndexChanged(int)"), \
268                             self.updateDevices)
269               
270                self.connect(self.pushButtonBluetoothSearch, \
271                                  QtCore.SIGNAL("clicked()"), \
272                                  self.updateDevices)
273               
274                self.connect(self.pushButtonSynapseServer, \
275                                  QtCore.SIGNAL("clicked()"), \
276                                  self.startSynapseServer)
277               
278                self.connect(self.pushButtonSave, \
279                                  QtCore.SIGNAL("clicked()"), \
280                                  self.saveData)
281               
282                self.connect(self.pushButtonExport, \
283                                  QtCore.SIGNAL("clicked()"), \
284                                  self.exportData)
285               
286                self.connect(self.pushButtonReset, \
287                                  QtCore.SIGNAL("clicked()"), \
288                                  self.resetData)
289       
290       
291        ##################################################################
292       
293        def startSynapseServer(self):
294               
295                eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
296                device_address = str(self.comboBoxDeviceSelect.currentText())
297                server_interface = str(self.lineEditSynapseHost.text())
298                server_port = int(self.lineEditSynapsePort.text())
299                #emulate_headset_data = (device_address == 'ThinkGear Emulator')
300               
301               
302                if (eeg_headset_model == 'Emotiv EPOC'):
303                        emulate_headset_data = True
304               
305               
306                #self.synapseServer = \
307                        #synapse_server.puzzlebox_synapse_server( \
308                                #self.log, \
309                                #server_interface=server_interface, \
310                                #server_port=server_port, \
311                                #device_model=eeg_headset_model, \
312                                #device_address=device_address, \
313                                #emulate_headset_data=emulate_headset_data, \
314                                #DEBUG=DEBUG, \
315                                #parent=self)
316               
317                #self.synapseServer.start()
318               
319               
320                if ((eeg_headset_model == 'NeuroSky MindWave') or \
321                    (eeg_headset_model == 'NeuroSky MindSet')):
322                       
323                        self.startThinkGearConnectService()
324               
325                elif (eeg_headset_model == 'Emotiv EPOC'):
326                       
327                        self.startEmotivService()
328               
329               
330               
331                if UPDATE_INTERFACE_VIA_TIMER:
332                        self.updateInterfaceTimer.start(INTERFACE_UPDATE_FREQUENCY)
333               
334                else:
335                        self.synapseClient = \
336                                synapse_client.puzzlebox_synapse_client( \
337                                        self.log, \
338                                        server_host=server_interface, \
339                                        server_port=server_port, \
340                                        DEBUG=0, \
341                                        parent=self)
342                       
343                        self.synapseClient.start()
344               
345               
346               
347                device_selection = self.comboBoxDeviceSelect.currentText()
348                self.textLabelBluetoothStatus.setText("Status: Connected")
349                self.pushButtonBluetoothSearch.setEnabled(False)
350                self.comboBoxDeviceSelect.setEnabled(False)
351                self.comboBoxEEGHeadsetModel.setEnabled(False)
352               
353                self.lineEditSynapseHost.setEnabled(False)
354                self.lineEditSynapsePort.setEnabled(False)
355               
356                self.pushButtonSynapseServer.setText('Stop')
357               
358                self.progressBarEEGDelta.setValue(0)
359                self.progressBarEEGTheta.setValue(0)
360                self.progressBarEEGLowAlpha.setValue(0)
361                self.progressBarEEGHighAlpha.setValue(0)
362                self.progressBarEEGLowBeta.setValue(0)
363                self.progressBarEEGHighBeta.setValue(0)
364                self.progressBarEEGLowGamma.setValue(0)
365                self.progressBarEEGMidGamma.setValue(0)
366               
367                self.progressBarAttention.setValue(0)
368                self.progressBarMeditation.setValue(0)
369               
370               
371                self.disconnect(self.pushButtonSynapseServer, \
372                                     QtCore.SIGNAL("clicked()"), \
373                                     self.startSynapseServer)
374               
375                self.connect(self.pushButtonSynapseServer, \
376                                  QtCore.SIGNAL("clicked()"), \
377                                  self.stopSynapseServer)
378       
379       
380        ##################################################################
381       
382        def stopSynapseServer(self):
383               
384                eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
385                device_address = str(self.comboBoxDeviceSelect.currentText())
386               
387                if ((eeg_headset_model == 'NeuroSky MindWave') or \
388                    (eeg_headset_model == 'NeuroSky MindSet')):
389                       
390                        self.stopThinkGearConnectService()
391               
392                elif (eeg_headset_model == 'Emotiv EPOC'):
393                       
394                        self.stopEmotivService()
395               
396               
397               
398                if UPDATE_INTERFACE_VIA_TIMER:
399                        self.updateInterfaceTimer.stop()
400                else:
401                        try:
402                                self.synapseClient.exitThread()
403                                #self.synapseClient.disconnectFromHost()
404                        except Exception, e:
405                                if self.DEBUG:
406                                        print "Call failed to self.synapseClient.exitThread():",
407                                        #print "Call failed to self.synapseClient.disconnectFromHost():",
408                                        print e
409               
410               
411               
412                if UPDATE_INTERFACE_VIA_TIMER:
413                        self.updateInterfaceTimer.stop()
414                else:
415                        try:
416                                self.synapseServer.exitThread()
417                        except Exception, e:
418                                if self.DEBUG:
419                                        print "Call failed to self.synapseServer.exitThread():",
420                                        print e
421               
422               
423                self.disconnect(self.pushButtonSynapseServer, \
424                                QtCore.SIGNAL("clicked()"), \
425                                self.stopSynapseServer)
426               
427                self.connect(self.pushButtonSynapseServer, \
428                                  QtCore.SIGNAL("clicked()"), \
429                                  self.startSynapseServer)
430               
431                self.lineEditSynapseHost.setEnabled(True)
432                self.lineEditSynapsePort.setEnabled(True)
433               
434                self.pushButtonSynapseServer.setText('Start')
435               
436                self.pushButtonBluetoothSearch.setEnabled(True)
437               
438                self.pushButtonSynapseServer.setChecked(False)
439               
440                self.textLabelBluetoothStatus.setText("Status: Disconnected")
441               
442                self.pushButtonBluetoothSearch.setEnabled(True)
443               
444                self.comboBoxDeviceSelect.setEnabled(True)
445                self.comboBoxEEGHeadsetModel.setEnabled(True)
446               
447               
448                self.progressBarEEGDelta.setValue(0)
449                self.progressBarEEGTheta.setValue(0)
450                self.progressBarEEGLowAlpha.setValue(0)
451                self.progressBarEEGHighAlpha.setValue(0)
452                self.progressBarEEGLowBeta.setValue(0)
453                self.progressBarEEGHighBeta.setValue(0)
454                self.progressBarEEGLowGamma.setValue(0)
455                self.progressBarEEGMidGamma.setValue(0)
456               
457                self.progressBarAttention.setValue(0)
458                self.progressBarMeditation.setValue(0)
459               
460                self.progressBarSignalContactQuality.setValue(0)
461               
462                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
463               
464                # In case the user connects to a MindSet, then disconnects
465                # and re-connects to a MindSet Emulator,
466                # we need to reset the max power values
467                self.progressBarEEGDelta.setMaximum(self.maxEEGPower)
468                self.progressBarEEGTheta.setMaximum(self.maxEEGPower)
469                self.progressBarEEGLowAlpha.setMaximum(self.maxEEGPower)
470                self.progressBarEEGHighAlpha.setMaximum(self.maxEEGPower)
471                self.progressBarEEGLowBeta.setMaximum(self.maxEEGPower)
472                self.progressBarEEGHighBeta.setMaximum(self.maxEEGPower)
473                self.progressBarEEGLowGamma.setMaximum(self.maxEEGPower)
474                self.progressBarEEGMidGamma.setMaximum(self.maxEEGPower)
475       
476       
477        ##################################################################
478       
479        def startThinkGearConnectService(self):
480               
481                server_interface = str(self.lineEditSynapseHost.text())
482                server_port = int(self.lineEditSynapsePort.text())
483                eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
484                device_address = str(self.comboBoxDeviceSelect.currentText())
485                emulate_headset_data = (device_address == 'ThinkGear Emulator')
486               
487               
488                self.synapseServer = \
489                        thinkgear_server.puzzlebox_synapse_server_thinkgear( \
490                                self.log, \
491                                server_interface=server_interface, \
492                                server_port=server_port, \
493                                device_model=eeg_headset_model, \
494                                device_address=device_address, \
495                                emulate_headset_data=emulate_headset_data, \
496                                DEBUG=DEBUG, \
497                                parent=self)
498               
499                self.synapseServer.start()
500               
501               
502                #if UPDATE_INTERFACE_VIA_TIMER:
503                        #self.updateInterfaceTimer.start(INTERFACE_UPDATE_FREQUENCY)
504               
505                #else:
506                        #self.thinkgearConnectClient = \
507                                #thinkgear_client.puzzlebox_synapse_thinkgear_client( \
508                                        #self.log, \
509                                        #server_host=server_interface, \
510                                        #server_port=server_port, \
511                                        #DEBUG=0, \
512                                        #parent=self)
513                       
514                        #self.thinkgearConnectClient.start()
515       
516       
517        ##################################################################
518       
519        def stopThinkGearConnectService(self):
520               
521                #if UPDATE_INTERFACE_VIA_TIMER:
522                        #self.updateInterfaceTimer.stop()
523                #else:
524                        #try:
525                                #self.thinkgearConnectClient.exitThread()
526                                ##self.thinkgearConnectClient.disconnectFromHost()
527                        #except Exception, e:
528                                #if self.DEBUG:
529                                        #print "Call failed to self.thinkgearConnectClient.exitThread():",
530                                        ##print "Call failed to self.thinkgearConnectClient.disconnectFromHost():",
531                                        #print e
532               
533                pass
534       
535       
536        ##################################################################
537       
538        def startEmotivService(self):
539               
540                #eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
541                device_address = str(self.comboBoxDeviceSelect.currentText())
542               
543                #server_host = configuration.EMOTIV_SERVER_HOST
544               
545                if device_address == 'Emotiv EPOC':
546                        #server_port = configuration.EMOTIV_SERVER_PORT_CONTROL_PANEL
547                        device_address = configuration.EMOTIV_SERVER_PORT_CONTROL_PANEL
548                else:
549                        #server_port = configuration.EMOTIV_SERVER_PORT_EMOCOMPOSER
550                        device_address = configuration.EMOTIV_SERVER_PORT_EMOCOMPOSER
551               
552                #self.emotivClient = \
553                   #emotiv_client.puzzlebox_synapse_client_emotiv( \
554                      #log=self.log, \
555                      #server_host=server_host, \
556                      #server_port=server_port, \
557                      #DEBUG=DEBUG, \
558                      #parent=self)
559               
560                #self.emotivClient.start()
561               
562               
563               
564                server_interface = str(self.lineEditSynapseHost.text())
565                server_port = int(self.lineEditSynapsePort.text())
566                eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
567                #device_address = str(self.comboBoxDeviceSelect.currentText())
568                emulate_headset_data = (device_address == 'ThinkGear Emulator')
569               
570               
571                self.synapseServer = \
572                        emotiv_server.puzzlebox_synapse_server_emotiv( \
573                                self.log, \
574                                server_interface=server_interface, \
575                                server_port=server_port, \
576                                device_model=eeg_headset_model, \
577                                device_address=device_address, \
578                                emulate_headset_data=emulate_headset_data, \
579                                DEBUG=DEBUG, \
580                                parent=self)
581               
582                self.synapseServer.start()
583               
584               
585               
586                self.progressBarEEGDelta.setEnabled(False)
587                self.progressBarEEGTheta.setEnabled(False)
588                self.progressBarEEGLowAlpha.setEnabled(False)
589                self.progressBarEEGHighAlpha.setEnabled(False)
590                self.progressBarEEGLowBeta.setEnabled(False)
591                self.progressBarEEGHighBeta.setEnabled(False)
592                self.progressBarEEGLowGamma.setEnabled(False)
593                self.progressBarEEGMidGamma.setEnabled(False)
594               
595                self.progressBarAttention.setEnabled(False)
596                self.progressBarMeditation.setEnabled(False)
597       
598       
599        ##################################################################
600       
601        def stopEmotivService(self):
602               
603                #self.emotivClient.stop()
604               
605                self.progressBarEEGDelta.setEnabled(True)
606                self.progressBarEEGTheta.setEnabled(True)
607                self.progressBarEEGLowAlpha.setEnabled(True)
608                self.progressBarEEGHighAlpha.setEnabled(True)
609                self.progressBarEEGLowBeta.setEnabled(True)
610                self.progressBarEEGHighBeta.setEnabled(True)
611                self.progressBarEEGLowGamma.setEnabled(True)
612                self.progressBarEEGMidGamma.setEnabled(True)
613               
614                self.progressBarAttention.setEnabled(True)
615                self.progressBarMeditation.setEnabled(True)
616       
617       
618        ##################################################################
619       
620        def updateInterface(self):
621               
622                if not self.synapseServer.emulate_headset_data:
623                        self.processPacketThinkGear( \
624                                self.synapseServer.protocol.data_packet)
625       
626       
627        ##################################################################
628       
629        def processPacket(self, packet):
630               
631                self.processPacketThinkGear(packet)
632                self.processPacketEmotiv(packet)
633               
634               
635                #if ((self.synapseServer.protocol != None) and
636                if (self.tabWidget.currentIndex() == \
637                    self.tabWidget.indexOf(self.tabControlPanel)):
638                       
639                        self.updateProfileSessionStatus()
640       
641       
642        ##################################################################
643       
644        def processPacketThinkGear(self, packet):
645               
646                #if self.DEBUG > 2:
647                        #print packet
648               
649               
650                if ('rawEeg' in packet.keys()):
651                        self.packets['rawEeg'].append(packet['rawEeg'])
652                        value = packet['rawEeg']
653                        if MATPLOTLIB_AVAILABLE and \
654                                (self.tabWidget.currentIndex() == \
655                                 self.tabWidget.indexOf(self.tabEEGSignals)):
656                                self.rawEEGMatplot.update_figure(value)
657                        return
658                else:
659                        self.packets['signals'].append(packet)
660               
661               
662                if ('poorSignalLevel' in packet.keys()):
663                        value = 200 - packet['poorSignalLevel']
664                        self.progressBarSignalContactQuality.setValue(value)
665                        self.textEditDebugConsole.append("")
666                        try:
667                                (date, localtime) = self.parseTimeStamp(packet['timestamp'])
668                                self.textEditDebugConsole.append("Timestamp: %s %s" % (date, localtime))
669                        except:
670                                pass
671                        self.textEditDebugConsole.append("poorSignalLevel: %i" % \
672                                                         packet['poorSignalLevel'])
673               
674               
675                if ('eSense' in packet.keys()):
676                       
677                        if ('attention' in packet['eSense'].keys()):
678                                value = packet['eSense']['attention']
679                                self.progressBarAttention.setValue(value)
680                                self.textEditDebugConsole.append("eSense attention: %i" % value)
681                       
682                        if ('meditation' in packet['eSense'].keys()):
683                                value = packet['eSense']['meditation']
684                                self.progressBarMeditation.setValue(value)
685                                self.textEditDebugConsole.append("eSense meditation: %i" % value)
686                       
687                       
688                        if MATPLOTLIB_AVAILABLE:
689                                self.chartEEGMatplot.update_values('eSense', packet['eSense'])
690                                if (self.tabWidget.currentIndex() == \
691                                    self.tabWidget.indexOf(self.tabCharts)):
692                                        self.chartEEGMatplot.update_figure('eSense', packet['eSense'])
693               
694               
695                if ('eegPower' in packet.keys()):
696                       
697                        # If we are not emulating packets we'll set the maximum EEG Power value
698                        # threshold to the default (or maximum value found within this packet)
699                        if not self.synapseServer.emulate_headset_data:
700                                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
701                       
702                        for value in packet['eegPower'].keys():
703                                if packet['eegPower'][value] > self.maxEEGPower:
704                                        self.maxEEGPower = packet['eegPower'][value]
705                       
706                       
707                        if ('delta' in packet['eegPower'].keys()):
708                                value = packet['eegPower']['delta']
709                                self.progressBarEEGDelta.setMaximum(self.maxEEGPower)
710                                self.progressBarEEGDelta.setValue(value)
711                                self.textEditDebugConsole.append("delta: %i" % value)
712                       
713                        if ('theta' in packet['eegPower'].keys()):
714                                value = packet['eegPower']['theta']
715                                self.progressBarEEGTheta.setMaximum(self.maxEEGPower)
716                                self.progressBarEEGTheta.setValue(value)
717                                self.textEditDebugConsole.append("theta: %i" % value)
718                       
719                        if ('lowAlpha' in packet['eegPower'].keys()):
720                                value = packet['eegPower']['lowAlpha']
721                                self.progressBarEEGLowAlpha.setMaximum(self.maxEEGPower)
722                                self.progressBarEEGLowAlpha.setValue(value)
723                                self.textEditDebugConsole.append("lowAlpha: %i" % value)
724                       
725                        if ('highAlpha' in packet['eegPower'].keys()):
726                                value = packet['eegPower']['highAlpha']
727                                self.progressBarEEGHighAlpha.setMaximum(self.maxEEGPower)
728                                self.progressBarEEGHighAlpha.setValue(value)
729                                self.textEditDebugConsole.append("highAlpha: %i" % value)
730                       
731                        if ('lowBeta' in packet['eegPower'].keys()):
732                                value = packet['eegPower']['lowBeta']
733                                self.progressBarEEGLowBeta.setMaximum(self.maxEEGPower)
734                                self.progressBarEEGLowBeta.setValue(value)
735                                self.textEditDebugConsole.append("lowBeta: %i" % value)
736                       
737                        if ('highBeta' in packet['eegPower'].keys()):
738                                value = packet['eegPower']['highBeta']
739                                self.progressBarEEGHighBeta.setMaximum(self.maxEEGPower)
740                                self.progressBarEEGHighBeta.setValue(value)
741                                self.textEditDebugConsole.append("highBeta: %i" % value)
742                       
743                        if ('lowGamma' in packet['eegPower'].keys()):
744                                value = packet['eegPower']['lowGamma']
745                                self.progressBarEEGLowGamma.setMaximum(self.maxEEGPower)
746                                self.progressBarEEGLowGamma.setValue(value)
747                                self.textEditDebugConsole.append("lowGamma: %i" % value)
748                       
749                        if ('highGamma' in packet['eegPower'].keys()):
750                                value = packet['eegPower']['highGamma']
751                                self.progressBarEEGMidGamma.setMaximum(self.maxEEGPower)
752                                self.progressBarEEGMidGamma.setValue(value)
753                                self.textEditDebugConsole.append("highGamma: %i" % value)
754                       
755                       
756                        if MATPLOTLIB_AVAILABLE:
757                                self.chartEEGMatplot.update_values('eegPower', packet['eegPower'])
758                                if (self.tabWidget.currentIndex() == \
759                                    self.tabWidget.indexOf(self.tabCharts)):
760                                        self.chartEEGMatplot.update_figure('eegPower', packet['eegPower'])
761               
762               
763                ##if ((self.synapseServer.protocol != None) and
764                #if (self.tabWidget.currentIndex() == \
765                    #self.tabWidget.indexOf(self.tabControlPanel)):
766                       
767                        #self.updateProfileSessionStatus()
768       
769       
770        ##################################################################
771       
772        def processPacketEmotiv(self, packet):
773               
774                if self.DEBUG > 2:
775                        print "INFO [Synapse:Interface] Emotiv packet received:"
776                        print packet
777               
778               
779                if ('emotivStatus' in packet.keys()):
780                       
781                        if ('timeFromStart' in packet['emotivStatus']):
782                                if not configuration.EMULATE_THINKGEAR_FOR_EMOTIV:
783                                        self.textEditDebugConsole.append("")
784                                        try:
785                                                (date, localtime) = self.parseTimeStamp(packet['timestamp'])
786                                                self.textEditDebugConsole.append("Timestamp: %s %s" % (date, localtime))
787                                        except:
788                                                pass
789                                self.textEditDebugConsole.append("timeFromStart: %f" % \
790                                                                  packet['emotivStatus']['timeFromStart'])
791                       
792                        if ('headsetOn' in packet['emotivStatus']):
793                                self.textEditDebugConsole.append("headsetOn: %s" % \
794                                                                  bool(packet['emotivStatus']['headsetOn']))
795                       
796                        if ('contactNumberOfQualityChannels' in packet['emotivStatus']):
797                                self.textEditDebugConsole.append("contactNumberOfQualityChannels: %i" % \
798                                                                  packet['emotivStatus']['contactNumberOfQualityChannels'])
799                       
800                        if ('wireless' in packet['emotivStatus']):
801                                self.textEditDebugConsole.append("wireless: %i" % \
802                                                                  packet['emotivStatus']['wireless'])
803               
804               
805                if ('affectiv' in packet.keys()):
806                       
807                        if ('excitement' in packet['affectiv']):
808                                self.textEditDebugConsole.append("excitement: %.2f" % \
809                                                                  packet['affectiv']['excitement'])
810                       
811                        if ('longTermExcitement' in packet['affectiv']):
812                                self.textEditDebugConsole.append("longTermExcitement: %.2f" % \
813                                                                  packet['affectiv']['longTermExcitement'])
814                       
815                        if ('meditation' in packet['affectiv']):
816                                self.textEditDebugConsole.append("meditation: %.2f" % \
817                                                                  packet['affectiv']['meditation'])
818                       
819                        if ('frustration' in packet['affectiv']):
820                                self.textEditDebugConsole.append("frustration: %.2f" % \
821                                                                  packet['affectiv']['frustration'])
822                       
823                        if ('engagementBoredom' in packet['affectiv']):
824                                self.textEditDebugConsole.append("engagementBoredom: %.2f" % \
825                                                                  packet['affectiv']['engagementBoredom'])
826               
827               
828                if ('cognitiv' in packet.keys()):
829                       
830                        if ('currentAction' in packet['cognitiv']):
831                                self.textEditDebugConsole.append("currentAction: %i" % \
832                                                                  packet['cognitiv']['currentAction'])
833                       
834                        if ('currentActionPower' in packet['cognitiv']):
835                                self.textEditDebugConsole.append("currentActionPower: %.2f" % \
836                                                                  packet['cognitiv']['currentActionPower'])
837       
838       
839        ##################################################################
840       
841        def updateProfileSessionStatus(self, source=None, target=None):
842               
843                session_time = self.calculateSessionTime()
844               
845                if source == None:
846                        if self.parent == None:
847                                source = self
848                        else:
849                                source = self.parent
850               
851                if target == None:
852                        if self.parent == None:
853                                target = self
854                        else:
855                                target = self.parent
856               
857                target.textLabelSessionTime.setText(session_time)
858               
859                try:
860                        target.textLabelPacketsReceived.setText( "%i" % \
861                                source.synapseServer.protocol.packet_count)
862                except:
863                        pass
864               
865                try:
866                        target.textLabelPacketsDropped.setText( "%i" % \
867                                source.synapseServer.protocol.bad_packets)
868                except:
869                        pass
870       
871       
872        ##################################################################
873       
874        def calculateSessionTime(self):
875               
876                if self.parent == None:
877                        server = self.synapseServer
878                else:
879                        server = self.parent.synapseServer
880               
881                session_time = time.time() - \
882                        server.session_start_timestamp
883                        #server.protocol.session_start_timestamp
884               
885                session_time = int(session_time)
886               
887                session_time = self.convert_seconds_to_datetime(session_time)
888               
889                return(session_time)
890       
891       
892        ##################################################################
893       
894        def enumerateSerialPorts(self):
895               
896                """ Uses the Win32 registry to return an
897                iterator of serial (COM) ports
898                existing on this computer.
899               
900                from http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
901                """
902         
903                path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
904                try:
905                        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
906                except WindowsError:
907                        #raise IterationError
908                        return
909               
910                for i in itertools.count():
911                        try:
912                                val = winreg.EnumValue(key, i)
913                                yield str(val[1])
914                        except EnvironmentError:
915                                break
916       
917       
918        ##################################################################
919       
920        def fullPortName(self, portname):
921               
922                """ Given a port-name (of the form COM7,
923                COM12, CNCA0, etc.) returns a full
924                name suitable for opening with the
925                Serial class.
926                """
927               
928                m = re.match('^COM(\d+)$', portname)
929                if m and int(m.group(1)) < 10:
930                        return portname
931               
932                return '\\\\.\\' + portname
933       
934       
935        ##################################################################
936       
937        def searchForSerialDevices(self, devices=[]):
938               
939                if (sys.platform == 'win32'):
940                       
941                        for portname in self.enumerateSerialPorts():
942                               
943                                if portname not in devices:
944                                        #portname = self.fullPortName(portname)
945                                        devices.append(portname)
946               
947                else:
948                       
949                       
950                        if os.path.exists('/dev/tty.MindWaveMobile-SPPDev'):
951                                devices.append('/dev/tty.MindWaveMobile-SPPDev')
952                       
953                        if os.path.exists('/dev/tty.MindWave'):
954                                devices.append('/dev/tty.MindWave')
955                        if os.path.exists('/dev/tty.MindWave1'):
956                                devices.append('/dev/tty.MindWave1')
957                        if os.path.exists('/dev/tty.MindWave2'):
958                                devices.append('/dev/tty.MindWave2')
959                        if os.path.exists('/dev/tty.MindWave3'):
960                                devices.append('/dev/tty.MindWave3')
961                        if os.path.exists('/dev/tty.MindWave4'):
962                                devices.append('/dev/tty.MindWave4')
963                        if os.path.exists('/dev/tty.MindWave5'):
964                                devices.append('/dev/tty.MindWave5')
965                       
966                        if os.path.exists('/dev/tty.MindSet-DevB'):
967                                devices.append('/dev/tty.MindSet-DevB')
968                       
969                        if os.path.exists('/dev/ttyUSB0'):
970                                devices.append('/dev/ttyUSB0')
971                        if os.path.exists('/dev/ttyUSB1'):
972                                devices.append('/dev/ttyUSB1')
973                        if os.path.exists('/dev/ttyUSB2'):
974                                devices.append('/dev/ttyUSB2')
975                        if os.path.exists('/dev/ttyUSB3'):
976                                devices.append('/dev/ttyUSB3')
977                        if os.path.exists('/dev/ttyUSB4'):
978                                devices.append('/dev/ttyUSB4')
979                        if os.path.exists('/dev/ttyUSB5'):
980                                devices.append('/dev/ttyUSB5')
981                        if os.path.exists('/dev/ttyUSB6'):
982                                devices.append('/dev/ttyUSB6')
983                        if os.path.exists('/dev/ttyUSB7'):
984                                devices.append('/dev/ttyUSB7')
985                        if os.path.exists('/dev/ttyUSB8'):
986                                devices.append('/dev/ttyUSB8')
987                        if os.path.exists('/dev/ttyUSB9'):
988                                devices.append('/dev/ttyUSB9')
989                       
990                        if os.path.exists('/dev/rfcomm0'):
991                                devices.append('/dev/rfcomm0')
992                        if os.path.exists('/dev/rfcomm1'):
993                                devices.append('/dev/rfcomm1')
994                        if os.path.exists('/dev/rfcomm2'):
995                                devices.append('/dev/rfcomm2')
996                        if os.path.exists('/dev/rfcomm3'):
997                                devices.append('/dev/rfcomm3')
998                        if os.path.exists('/dev/rfcomm4'):
999                                devices.append('/dev/rfcomm4')
1000                       
1001                        if os.path.exists('/dev/ttyACM0'):
1002                                devices.append('/dev/ttyACM0')
1003                        if os.path.exists('/dev/ttyACM1'):
1004                                devices.append('/dev/ttyACM1')
1005                        if os.path.exists('/dev/ttyACM2'):
1006                                devices.append('/dev/ttyACM2')
1007                        if os.path.exists('/dev/ttyACM3'):
1008                                devices.append('/dev/ttyACM3')
1009                        if os.path.exists('/dev/ttyACM4'):
1010                                devices.append('/dev/ttyACM4')
1011               
1012               
1013                return(devices)
1014       
1015       
1016        ##################################################################
1017       
1018        def hcitoolScanForRemoteDevices(self, devices=[]):
1019               
1020                bluetooth_devices = []
1021               
1022                #command = '%s scan 2> /dev/null' % PATH_TO_HCITOOL
1023                command = '%s scan' % PATH_TO_HCITOOL
1024               
1025                if self.DEBUG > 1:
1026                        print 'INFO: Calling "%s"' % command
1027               
1028                output = os.popen(command, 'r')
1029               
1030                try:
1031                        result = output.readlines()
1032                except Exception, e:
1033                        if self.DEBUG:
1034                                print "ERROR [Synapse-Interface]: Failed reading result from call to hcitool:",
1035                                print e
1036                        result = ''
1037               
1038                if result == '':
1039                        return([]) # Under OS X hcitool doesn't exist so we don't see any devices
1040               
1041                for line in result:
1042                        line = line.strip()
1043                        if line == '' or line == 'Scanning ...':
1044                                continue
1045                        elif self.DEBUG > 1:
1046                                print line
1047                        try:
1048                                address = line.split('\t')[0]
1049                        except:
1050                                pass
1051                        else:
1052                                bluetooth_devices.append(address)
1053               
1054               
1055                for address in bluetooth_devices:
1056                       
1057                        command = '%s name %s' % (PATH_TO_HCITOOL, address)
1058                       
1059                        if self.DEBUG:
1060                                print 'INFO: Calling "%s"' % command
1061                       
1062                        output = os.popen(command, 'r')
1063                       
1064                        for line in output.readlines():
1065                                line = line.strip()
1066                                if line == '':
1067                                        continue
1068                                elif self.DEBUG:
1069                                        print '\t',
1070                                        print line
1071                               
1072                                device_name = line.strip()
1073                       
1074                                if ((device_name == 'MindSet' or device_name == 'MindWave Mobile') and \
1075                                        (address not in devices)):
1076                                        devices.append(address)
1077                               
1078                                else:
1079                                        if self.DEBUG:
1080                                                print 'INFO: Found but not recognized: [%s] %s' % \
1081                                                        (address, device_name)
1082               
1083               
1084                return (devices)
1085       
1086       
1087        ##################################################################
1088       
1089        def hcitoolGetActiveConnections(self, devices=[]):
1090               
1091                bluetooth_devices = []
1092               
1093                #command = '%s con 2> /dev/null' % PATH_TO_HCITOOL
1094                command = '%s con' % PATH_TO_HCITOOL
1095               
1096                if self.DEBUG > 1:
1097                        print 'INFO: Calling "%s"' % command
1098               
1099                output = os.popen(command, 'r')
1100               
1101                try:
1102                        result = output.readlines()
1103                except Exception, e:
1104                        if self.DEBUG:
1105                                print "ERROR [Synapse:Interface]: Failed reading result from call to hcitool:",
1106                                print e
1107                        result = ''
1108
1109                if result == '':
1110                        return([]) # Under OS X hcitool doesn't exist so we don't see any devices
1111
1112                for line in result:
1113                        line = line.strip()
1114                        if line == '' or line == 'Connections:':
1115                                continue
1116                        elif self.DEBUG > 1:
1117                                print line
1118                        try:
1119                                address = line.split(' ')[2]
1120                        except:
1121                                pass
1122                        else:
1123                                bluetooth_devices.append(address)
1124               
1125               
1126                for address in bluetooth_devices:
1127                       
1128                        command = '%s name %s' % (PATH_TO_HCITOOL, address)
1129                       
1130                        if self.DEBUG:
1131                                print 'INFO: Calling "%s":' % command
1132                       
1133                        output = os.popen(command, 'r')
1134                       
1135                        for line in output.readlines():
1136                                line = line.strip()
1137                                if line == '':
1138                                        continue
1139                                elif self.DEBUG:
1140                                        print '\t',
1141                                        print line
1142                               
1143                                device_name = line.strip()
1144                       
1145                                if ((device_name == 'MindSet' or device_name == 'MindWave Mobile') and \
1146                                        (address not in devices)):
1147                                        devices.append(address)
1148               
1149               
1150                return (devices)
1151       
1152       
1153        ##################################################################
1154       
1155        def searchForDevices(self):
1156               
1157                enable_hcitool = configuration.ENABLE_HCITOOL
1158               
1159                devices = []
1160               
1161                #self.pushButtonBluetoothSearch.setText('Searching')
1162               
1163                if ((sys.platform != 'win32' and sys.platform != 'darwin') and \
1164                     configuration.THINKGEAR_BLUETOOTH_SEARCH):
1165                       
1166                        # Bluetooth module doesn't compile properly under Windows
1167                        # and doesn't exist under OS X
1168                       
1169                        # PyBluez API Documentation
1170                        # http://pybluez.googlecode.com/svn/www/docs-0.7/index.html
1171                       
1172                        bluetooth_devices = []
1173                       
1174                        if not enable_hcitool:
1175                               
1176                                try:
1177                                       
1178                                        if self.DEBUG:
1179                                                print "INFO: Searching for Bluetooth devices using PyBluez module"
1180                                       
1181                                        bluetooth_devices = bluetooth.discover_devices( \
1182                                              duration=configuration.THINKGEAR_BLUETOOTH_DISCOVER_DEVICES_TIMEOUT, \
1183                                                               flush_cache=True, \
1184                                                               lookup_names=False)
1185                                       
1186                                        for address in bluetooth_devices:
1187                                               
1188                                                if self.DEBUG:
1189                                                        print "INFO: Device discovered",
1190                                                        print address
1191                                               
1192                                                device_name = bluetooth.lookup_name(address, \
1193                                                                 configuration.THINKGEAR_BLUETOOTH_LOOKUP_NAME_TIMEOUT)
1194                                                if ((device_name == 'MindSet' or device_name == 'MindWave Mobile') and \
1195                                                        (address not in devices)):
1196                                                        devices.append(address)
1197                                       
1198                                       
1199                                        # There is an issue under recent released of Linux
1200                                        # in which already-connected Bluetooth ThinkGear devices
1201                                        # are not appearing in a bluetooth device scan. However,
1202                                        # using "hcitool" connected devices can be listed correctly.
1203                                        # There does not appear to be an equivalent PyBluez feature.
1204                                        # (http://pybluez.googlecode.com/svn/www/docs-0.7/index.html)
1205                                       
1206                                        if devices == []:
1207                                                if self.DEBUG:
1208                                                        print "INFO: No devices found through PyBluez module. Falling back to hcitool."
1209                                                devices = self.hcitoolGetActiveConnections(devices)
1210                               
1211                               
1212                                except Exception, e:
1213                                        if self.DEBUG:
1214                                                print "ERROR: Exception calling Python Bluetooth module. (Is PyBluez installed?):"
1215                                                print e
1216                                       
1217                                       
1218                                        #if (sys.platform != 'darwin'):
1219                                        enable_hcitool = True
1220                       
1221                       
1222                        if enable_hcitool:
1223                               
1224                                devices = self.hcitoolScanForRemoteDevices(devices)
1225                                devices = self.hcitoolGetActiveConnections(devices)
1226                       
1227                       
1228                        if self.DEBUG > 2:
1229                                print "Bluetooth Devices found:",
1230                                print devices
1231               
1232               
1233                devices = self.searchForSerialDevices(devices)
1234               
1235               
1236                if self.DEBUG:
1237                        print "Devices found:",
1238                        print devices
1239               
1240               
1241                return(devices)
1242       
1243       
1244        ##################################################################
1245       
1246        def updateDevices(self):
1247               
1248                model = self.comboBoxEEGHeadsetModel.currentText()
1249               
1250                devices = self.searchForDevices()
1251               
1252                self.comboBoxDeviceSelect.clear()
1253               
1254                if (model == 'NeuroSky MindWave' or \
1255                    model == 'NeuroSky MindSet' or \
1256                    model == 'NeuroSky MindWave Mobile'):
1257                       
1258                        devices.insert(0, 'ThinkGear Emulator')
1259               
1260                elif (model == 'Emotiv EPOC'):
1261                       
1262                        devices.insert(0, 'EmoComposer')
1263                        devices.insert(0, 'Emotiv Headset')
1264               
1265               
1266                for device in devices:
1267                        self.comboBoxDeviceSelect.addItem(device)
1268       
1269       
1270        ##################################################################
1271       
1272        def collectData(self, source=None, target=None):
1273               
1274                if source == None:
1275                        if self.parent == None:
1276                                source = self
1277                        else:
1278                                source = self.parent
1279               
1280                if target == None:
1281                        if self.parent == None:
1282                                target = self
1283                        else:
1284                                target = self.parent
1285               
1286                data = {}
1287               
1288                data['rawEeg'] = source.packets['rawEeg']
1289                data['signals'] = source.packets['signals']
1290               
1291                data['sessionTime'] = self.calculateSessionTime()
1292               
1293                data['profileName'] = str(target.lineEditSessionProfile.text())
1294               
1295                return(data)
1296       
1297       
1298        ##################################################################
1299       
1300        def parseTimeStamp(self, timestamp, local_version=False, truncate_time_zone=False):
1301               
1302                try:
1303                        decimal = '%f' % timestamp
1304                        decimal = decimal.split('.')[1]
1305                except:
1306                        decimal = '0'
1307               
1308                localtime = time.localtime(timestamp)
1309               
1310                if local_version:
1311                        date = time.strftime('%x', localtime)
1312                        localtime = time.strftime('%X', localtime)
1313               
1314                elif truncate_time_zone:
1315                        date = time.strftime('%Y-%m-%d', localtime)
1316                        localtime = time.strftime('%H:%M:%S', localtime)
1317                        localtime = '%s.%s' % (localtime, decimal[:3])
1318               
1319                else:
1320                        date = time.strftime('%Y-%m-%d', localtime)
1321                        localtime = time.strftime('%H:%M:%S', localtime)
1322                        localtime = '%s.%s %s' % (localtime, decimal, \
1323                                       time.strftime('%Z', time.localtime(timestamp)))
1324               
1325               
1326                return(date, localtime)
1327       
1328       
1329        ##################################################################
1330       
1331        def saveData(self, source=None, target=None, output_file=None, use_default=False):
1332               
1333                if source == None:
1334                        if self.parent == None:
1335                                source = self
1336                        else:
1337                                source = self.parent
1338               
1339                if target == None:
1340                        if self.parent == None:
1341                                target = self
1342                        else:
1343                                target = self.parent
1344               
1345                data = self.collectData(source=source, target=target)
1346               
1347                (date, localtime) = self.parseTimeStamp(time.time())
1348               
1349                default_filename = '%s %s.synapse' % (date, \
1350                                      target.lineEditSessionProfile.text())
1351                                     
1352                default_filename = os.path.join(self.homepath, default_filename)
1353               
1354                if output_file == None:
1355                       
1356                        # use_default controls whether or not a file is automatically saves using the
1357                        # default name and path (as opposed to raising a GUI file selection menu)
1358                        # whenever an explicit filepath is not defined
1359                        if use_default:
1360                                       
1361                                        output_file = default_filename
1362                       
1363                        else:
1364                       
1365                                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
1366                                                 caption="Save Session Data to File", \
1367                                                 dir=default_filename, \
1368                                                 filter="Puzzlebox Synapse Data File (*.synapse)")
1369                               
1370                                try:
1371                                        output_file = output_file[0]
1372                                except:
1373                                        output_file = ''
1374               
1375               
1376                if output_file == '':
1377                        return
1378               
1379                file = open(str(output_file), 'w')
1380                pickle.dump(data, file)
1381                file.close()
1382       
1383       
1384        ##################################################################
1385       
1386        def exportData(self, parent=None, source=None, target=None, output_file=None, use_default=False):
1387               
1388                if parent == None:
1389                        if self.parent == None:
1390                                parent = self
1391                        else:
1392                                parent = self.parent
1393               
1394                if source == None:
1395                        if self.parent == None:
1396                                source = self
1397                        else:
1398                                source = self.parent
1399               
1400                if target == None:
1401                        if self.parent == None:
1402                                target = self
1403                        else:
1404                                target = self.parent
1405               
1406               
1407                (date, localtime) = self.parseTimeStamp(time.time())
1408               
1409                default_filename = '%s %s.csv' % (date, \
1410                                      target.lineEditSessionProfile.text())
1411               
1412                default_filename = os.path.join(target.homepath, default_filename)
1413               
1414               
1415                if output_file == None:
1416                       
1417                        # use_default controls whether or not a file is automatically saves using the
1418                        # default name and path (as opposed to raising a GUI file selection menu)
1419                        # whenever an explicit filepath is not defined
1420                        if use_default:
1421                                       
1422                                        output_file = default_filename
1423                       
1424                        else:
1425                                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
1426                                                 caption="Export Session Data to File", \
1427                                                 dir=default_filename, \
1428                                                 filter="CSV File (*.csv);;Text File (*.txt)")
1429                               
1430                                try:
1431                                        output_file = output_file[0]
1432                                except:
1433                                        output_file = ''
1434               
1435               
1436                if output_file == '':
1437                        return
1438               
1439               
1440                if str(output_file).endswith('.csv'):
1441                       
1442                        outputData = self.exportDataToCSV(parent=parent, source=source, target=target)
1443               
1444               
1445                else:
1446                       
1447                        try:
1448                                outputData = self.textEditDebugConsole.toPlainText()
1449                        except:
1450                                outputData = self.exportDataToCSV()
1451               
1452               
1453                file = open(str(output_file), 'w')
1454                file.write(outputData)
1455                file.close()
1456       
1457       
1458        ##################################################################
1459       
1460        def exportDataToCSV(self, parent=None, source=None, target=None):
1461               
1462                if parent == None:
1463                        if self.parent == None:
1464                                parent = self
1465                        else:
1466                                parent = self.parent
1467               
1468                if source == None:
1469                        if self.parent == None:
1470                                source = self
1471                        else:
1472                                source = self.parent
1473               
1474                if target == None:
1475                        if self.parent == None:
1476                                target = self
1477                        else:
1478                                target = self.parent
1479               
1480                try:
1481                        truncate_csv_timezone = target.configuration.EXPORT_CSV_TRUNCATE_TIMEZONE
1482                except:
1483                        truncate_csv_timezone = False
1484               
1485                try:
1486                        scrub_data = target.configuration.EXPORT_CSV_SCRUB_DATA
1487                except:
1488                        scrub_data = False
1489               
1490               
1491                headers = 'Date,Time,Attention,Meditation,Signal Level,Delta,Theta,Low Alpha,High Alpha,Low Beta,High Beta,Low Gamma,Mid Gamma'
1492               
1493                customDataHeaders = []
1494                for header in parent.customDataHeaders:
1495                        customDataHeaders.append(header)
1496                for plugin in parent.activePlugins:
1497                        for header in plugin.customDataHeaders:
1498                                customDataHeaders.append(header)
1499               
1500                for each in customDataHeaders:
1501                        headers = headers + ',%s' % each
1502               
1503                headers = headers + '\n'
1504               
1505                csv = {}
1506               
1507                for packet in source.packets['signals']:
1508                       
1509                       
1510                        if 'rawEeg' in packet.keys():
1511                                continue
1512                       
1513                        if packet['timestamp'] not in csv.keys():
1514                               
1515                                if 'blinkStrength' in packet.keys():
1516                                        # Skip any blink packets from log
1517                                        continue
1518                               
1519                               
1520                                #print packet
1521                                timestamp = packet['timestamp']
1522                                (date, localtime) = self.parseTimeStamp(timestamp, \
1523                                                    truncate_time_zone=truncate_csv_timezone)
1524                               
1525                                csv[timestamp] = {}
1526                                csv[timestamp]['Date'] = date
1527                                csv[timestamp]['Time'] = localtime
1528                                csv[timestamp]['Attention'] = ''
1529                                csv[timestamp]['Meditation'] = ''
1530                                csv[timestamp]['Signal Level'] = ''
1531                                csv[timestamp]['Delta'] = ''
1532                                csv[timestamp]['Theta'] = ''
1533                                csv[timestamp]['Low Alpha'] = ''
1534                                csv[timestamp]['High Alpha'] = ''
1535                                csv[timestamp]['Low Beta'] = ''
1536                                csv[timestamp]['High Beta'] = ''
1537                                csv[timestamp]['Low Gamma'] = ''
1538                                csv[timestamp]['Mid Gamma'] = ''
1539                               
1540                                for header in customDataHeaders:
1541                                        csv[timestamp][header] = ''
1542                       
1543                       
1544                        if 'eSense' in packet.keys():
1545                                if 'attention' in packet['eSense'].keys():
1546                                        csv[timestamp]['Attention'] = packet['eSense']['attention']
1547                                if 'meditation' in packet['eSense'].keys():
1548                                        csv[timestamp]['Meditation'] = packet['eSense']['meditation']
1549                       
1550                        if 'eegPower' in packet.keys():
1551                                if 'delta' in packet['eegPower'].keys():
1552                                        csv[timestamp]['Delta'] = packet['eegPower']['delta']
1553                                if 'theta' in packet['eegPower'].keys():
1554                                        csv[timestamp]['Theta'] = packet['eegPower']['theta']
1555                                if 'lowAlpha' in packet['eegPower'].keys():
1556                                        csv[timestamp]['Low Alpha'] = packet['eegPower']['lowAlpha']
1557                                if 'highAlpha' in packet['eegPower'].keys():
1558                                        csv[timestamp]['High Alpha'] = packet['eegPower']['highAlpha']
1559                                if 'lowBeta' in packet['eegPower'].keys():
1560                                        csv[timestamp]['Low Beta'] = packet['eegPower']['lowBeta']
1561                                if 'highBeta' in packet['eegPower'].keys():
1562                                        csv[timestamp]['High Beta'] = packet['eegPower']['highBeta']
1563                                if 'lowGamma' in packet['eegPower'].keys():
1564                                        csv[timestamp]['Low Gamma'] = packet['eegPower']['lowGamma']
1565                                if 'highGamma' in packet['eegPower'].keys():
1566                                        csv[timestamp]['Mid Gamma'] = packet['eegPower']['highGamma']
1567                       
1568                        if 'poorSignalLevel' in packet.keys():
1569                                csv[timestamp]['Signal Level'] = packet['poorSignalLevel']
1570                       
1571                        for header in customDataHeaders:
1572                                if 'custom' in packet.keys() and \
1573                                   header in packet['custom'].keys():
1574                                        csv[timestamp][header] = packet['custom'][header]
1575               
1576               
1577                if scrub_data:
1578                        csv = self.scrubData(csv, truncate_csv_timezone)
1579               
1580               
1581                output = headers
1582               
1583                csv_keys = csv.keys()
1584                csv_keys.sort()
1585               
1586                for key in csv_keys:
1587                       
1588                        row = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % \
1589                              (csv[key]['Date'], \
1590                               csv[key]['Time'], \
1591                               csv[key]['Attention'], \
1592                               csv[key]['Meditation'], \
1593                               csv[key]['Signal Level'], \
1594                               csv[key]['Delta'], \
1595                               csv[key]['Theta'], \
1596                               csv[key]['Low Alpha'], \
1597                               csv[key]['High Alpha'], \
1598                               csv[key]['Low Beta'], \
1599                               csv[key]['High Beta'], \
1600                               csv[key]['Low Gamma'], \
1601                               csv[key]['Mid Gamma'])
1602                       
1603                        for header in customDataHeaders:
1604                                row = row + ',%s' % csv[key][header]
1605                       
1606                        row = row + '\n'
1607                       
1608                        output = output + row
1609               
1610               
1611                return(output)
1612       
1613       
1614        ##################################################################
1615       
1616        def scrubData(self, csv, truncate_csv_timezone=False):
1617               
1618                # If there are missing packets, repeat a given packet once per missing
1619                # second until there is a gap between 1 and 2 seconds, in which case
1620                # produce a final duplicate packet at the mid-point between the packets
1621
1622                if self.DEBUG:
1623                        print "INFO: Scrubbing Data"
1624               
1625                last_time = None
1626                last_recorded_time = None
1627               
1628                output = {}
1629               
1630                csv_keys = csv.keys()
1631                csv_keys.sort()
1632               
1633                for key in csv_keys:
1634                       
1635                        timestamp = key
1636
1637                        if csv[key]['Attention'] == '':
1638                                continue
1639                       
1640                        if last_time == None:
1641                                # First entry in log
1642                                last_time = timestamp
1643                                last_recorded_time = timestamp
1644                                output[key] = csv[key]
1645                                continue
1646                       
1647                        else:
1648                               
1649                                #time_difference = timestamp - last_time
1650                                time_difference = timestamp - last_recorded_time
1651                               
1652                                if (time_difference <= 1) and \
1653                                   (time_difference >= PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD):
1654                                        # Skip packets within the correct time threshold
1655                                        last_time = timestamp
1656                                        last_recorded_time = timestamp
1657                                        output[key] = csv[key]
1658                                        continue
1659                               
1660                                else:
1661                                       
1662                                        if self.DEBUG > 1:
1663                                                print "time_difference:",
1664                                                print time_difference
1665                                                print "timestamp:",
1666                                                print self.parseTimeStamp(timestamp)[-1].split(' ')[0]
1667                                                print "last_time:",
1668                                                print self.parseTimeStamp(last_time)[-1].split(' ')[0]
1669                                                print "last_recorded_time:",
1670                                                print self.parseTimeStamp(last_recorded_time)[-1].split(' ')[0]
1671                                       
1672                                       
1673                                        new_packet = csv[key].copy()
1674                                       
1675                                        if time_difference >= 2:
1676                                               
1677                                                ##new_time = last_time + 1
1678                                                #new_time = last_recorded_time + 1
1679                                               
1680                                                count = int(time_difference)
1681                                                while count >= 1:
1682                                                        new_packet = csv[key].copy()
1683                                                        new_time = last_recorded_time + 1
1684                                                        (date, formatted_new_time) = self.parseTimeStamp(new_time, \
1685                                                         truncate_time_zone=truncate_csv_timezone)
1686                                                        new_packet['Time'] = formatted_new_time
1687                                                        last_recorded_time = new_time
1688                                                        last_time = timestamp
1689                                                        output[new_time] = new_packet
1690                                                        count = count - 1
1691                                                continue
1692                                               
1693                                        elif time_difference < PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD:
1694                                                # Spread out "bunched up" packets
1695                                                #new_time = last_time + 1
1696                                                new_time = last_recorded_time + 1
1697                                       
1698                                       
1699                                        elif (time_difference < 2) and (time_difference > 1):
1700                                               
1701                                                #new_time = last_time + ((last_time - timestamp) / 2)
1702                                                #new_time = last_recorded_time + ((last_recorded_time - timestamp) / 2)
1703                                                #new_time = last_time + 1
1704                                                new_time = last_recorded_time + 1
1705                                       
1706                                       
1707                                        (date, formatted_new_time) = self.parseTimeStamp(new_time, \
1708                                           truncate_time_zone=truncate_csv_timezone)
1709                                       
1710                                        new_packet['Time'] = formatted_new_time
1711                                       
1712                                        #last_time = new_time
1713                                        last_recorded_time = new_time
1714                                        last_time = timestamp
1715                                        output[new_time] = new_packet
1716                                       
1717                                        if self.DEBUG > 1:
1718                                                print "WARN: Scrubbing new packet:",
1719                                                print new_packet
1720                                                print
1721               
1722               
1723                return(output)
1724       
1725       
1726        ##################################################################
1727       
1728        def resetData(self, source=None):
1729               
1730                if source == None:
1731                        if self.parent == None:
1732                                source = self
1733                        else:
1734                                source = self.parent
1735               
1736                #if target == None:
1737                        #if self.parent == None:
1738                                #target = self
1739                        #else:
1740                                #target = self.parent
1741               
1742                source.packets['rawEeg'] = []
1743                source.packets['signals'] = []
1744               
1745                source.synapseServer.protocol.session_start_timestamp = \
1746                        time.time()
1747               
1748                source.synapseServer.protocol.packet_count = 0
1749                source.synapseServer.protocol.bad_packets = 0
1750               
1751                self.updateProfileSessionStatus()
1752               
1753                try:
1754                        source.textEditDebugConsole.setText("")
1755                except:
1756                        pass
1757       
1758       
1759        #####################################################################
1760       
1761        def convert_seconds_to_datetime(self, duration):
1762               
1763                duration_hours = duration / (60 * 60)
1764                duration_minutes = (duration - (duration_hours * (60 * 60))) / 60
1765                duration_seconds = (duration - (duration_hours * (60 * 60)) - (duration_minutes * 60))
1766               
1767                duration_hours = '%i' % duration_hours
1768                if (len(duration_hours) == 1):
1769                        duration_hours = "0%s" % duration_hours
1770               
1771                duration_minutes = '%i' % duration_minutes
1772                if (len(duration_minutes) == 1):
1773                        duration_minutes = "0%s" % duration_minutes
1774               
1775                duration_seconds = '%i' % duration_seconds
1776                if (len(duration_seconds) == 1):
1777                        duration_seconds = "0%s" % duration_seconds
1778               
1779                datetime = '%s:%s:%s' % (duration_hours, duration_minutes, duration_seconds)
1780               
1781                return(datetime)
1782       
1783       
1784        ##################################################################
1785       
1786        def stop(self):
1787               
1788                if UPDATE_INTERFACE_VIA_TIMER:
1789                        self.updateInterfaceTimer.stop()
1790                else:
1791                        #if self.thinkgearConnectClient != None:
1792                                #self.thinkgearConnectClient.exitThread()
1793                        #if self.emotivClient != None:
1794                                #self.emotivClient.exitThread()
1795                        if self.synapseClient != None:
1796                                self.synapseClient.exitThread()
1797               
1798                if self.synapseServer != None:
1799                        self.synapseServer.exitThread()
1800       
1801       
1802        ##################################################################
1803       
1804        def closeEvent(self, event):
1805               
1806                quit_message = "Are you sure you want to exit the program?"
1807               
1808                reply = QtGui.QMessageBox.question( \
1809                           self, \
1810                          'Message', \
1811                           quit_message, \
1812                           QtGui.QMessageBox.Yes, \
1813                           QtGui.QMessageBox.No)
1814               
1815                if reply == QtGui.QMessageBox.Yes:
1816                       
1817                        self.stop()
1818                       
1819                        event.accept()
1820               
1821                else:
1822                        event.ignore()
Note: See TracBrowser for help on using the repository browser.