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

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