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

Last change on this file since 353 was 353, checked in by sc, 9 years ago

Interface:

  • Updated object name
  • displays devices defaults based on manufacturer of selected model
  • 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 puzzlebox_synapse_interface(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.updateDevices()
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.comboBoxEEGHeadsetModel, \
271                             QtCore.SIGNAL("currentIndexChanged(int)"), \
272                             self.updateDevices)
273               
274                self.connect(self.pushButtonBluetoothSearch, \
275                                  QtCore.SIGNAL("clicked()"), \
276                                  self.updateDevices)
277               
278                self.connect(self.pushButtonBluetoothConnect, \
279                                  QtCore.SIGNAL("clicked()"), \
280                                  self.connectToThinkGearDevice)
281               
282                self.connect(self.pushButtonThinkGearConnect, \
283                                  QtCore.SIGNAL("clicked()"), \
284                                  self.startSynapseServer)
285               
286                self.connect(self.pushButtonSave, \
287                                  QtCore.SIGNAL("clicked()"), \
288                                  self.saveData)
289               
290                self.connect(self.pushButtonExport, \
291                                  QtCore.SIGNAL("clicked()"), \
292                                  self.exportData)
293               
294                self.connect(self.pushButtonReset, \
295                                  QtCore.SIGNAL("clicked()"), \
296                                  self.resetData)
297       
298       
299        ##################################################################
300       
301        def connectToThinkGearDevice(self):
302               
303                device_selection = self.comboBoxDeviceSelect.currentText()
304               
305                self.disconnect(self.pushButtonBluetoothConnect, \
306                                     QtCore.SIGNAL("clicked()"), \
307                                     self.connectToThinkGearDevice)
308               
309                self.connect(self.pushButtonBluetoothConnect, \
310                                  QtCore.SIGNAL("clicked()"), \
311                                  self.disconnectFromThinkGearDevice)
312               
313                self.textLabelBluetoothStatus.setText("Status: Connected")
314               
315                self.pushButtonBluetoothSearch.setEnabled(False)
316               
317                self.pushButtonBluetoothConnect.setText('Disconnect')
318                self.pushButtonBluetoothConnect.setChecked(True)
319               
320                self.comboBoxDeviceSelect.setEnabled(False)
321                self.comboBoxEEGHeadsetModel.setEnabled(False)
322       
323       
324        ##################################################################
325       
326        def disconnectFromThinkGearDevice(self):
327               
328                self.disconnect(self.pushButtonBluetoothConnect, \
329                                     QtCore.SIGNAL("clicked()"), \
330                                     self.disconnectFromThinkGearDevice)
331               
332                self.connect(self.pushButtonBluetoothConnect, \
333                                  QtCore.SIGNAL("clicked()"), \
334                                  self.connectToThinkGearDevice)
335               
336                self.textLabelBluetoothStatus.setText("Status: Disconnected")
337               
338                self.pushButtonBluetoothSearch.setEnabled(True)
339               
340                self.pushButtonBluetoothConnect.setText('Connect')
341                self.pushButtonBluetoothConnect.setChecked(False)
342               
343                self.comboBoxDeviceSelect.setEnabled(True)
344                self.comboBoxEEGHeadsetModel.setEnabled(True)
345               
346               
347                self.progressBarEEGDelta.setValue(0)
348                self.progressBarEEGTheta.setValue(0)
349                self.progressBarEEGLowAlpha.setValue(0)
350                self.progressBarEEGHighAlpha.setValue(0)
351                self.progressBarEEGLowBeta.setValue(0)
352                self.progressBarEEGHighBeta.setValue(0)
353                self.progressBarEEGLowGamma.setValue(0)
354                self.progressBarEEGMidGamma.setValue(0)
355               
356                self.progressBarAttention.setValue(0)
357                self.progressBarMeditation.setValue(0)
358               
359                self.progressBarSignalContactQuality.setValue(0)
360               
361                self.maxEEGPower = THINKGEAR_EMULATION_MAX_EEG_POWER_VALUE
362               
363                # In case the user connects to a MindSet, then disconnects
364                # and re-connects to a MindSet Emulator,
365                # we need to reset the max power values
366                self.progressBarEEGDelta.setMaximum(self.maxEEGPower)
367                self.progressBarEEGTheta.setMaximum(self.maxEEGPower)
368                self.progressBarEEGLowAlpha.setMaximum(self.maxEEGPower)
369                self.progressBarEEGHighAlpha.setMaximum(self.maxEEGPower)
370                self.progressBarEEGLowBeta.setMaximum(self.maxEEGPower)
371                self.progressBarEEGHighBeta.setMaximum(self.maxEEGPower)
372                self.progressBarEEGLowGamma.setMaximum(self.maxEEGPower)
373                self.progressBarEEGMidGamma.setMaximum(self.maxEEGPower)
374       
375       
376        ##################################################################
377       
378        def startSynapseServer(self):
379               
380                eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
381                device_address = str(self.comboBoxDeviceSelect.currentText())
382               
383                if ((eeg_headset_model == 'NeuroSky MindWave') or \
384                    (eeg_headset_model == 'NeuroSky MindSet')):
385                       
386                        self.startThinkGearConnectServer()
387               
388                elif (eeg_headset_model == 'Emotiv EPOC'):
389                       
390                        self.startEmotivServer()
391       
392       
393        ##################################################################
394       
395        def processPacketEmotiv(self, packet):
396               
397                print
398                print "Booyah"
399                print
400                print packet
401                print
402                print
403       
404       
405        ##################################################################
406       
407        def startEmotivServer(self):
408               
409                eeg_headset_model = str(self.comboBoxEEGHeadsetModel.currentText())
410                device_address = str(self.comboBoxDeviceSelect.currentText())
411               
412                server_host = configuration.EMOTIV_SERVER_HOST
413               
414                if device_address == 'Emotiv EPOC':
415                        server_port = configuration.EMOTIV_SERVER_PORT_CONTROL_PANEL
416                else:
417                        server_port = configuration.EMOTIV_SERVER_PORT_EMOCOMPOSER
418               
419                self.emotivClient = \
420                   emotiv_client.puzzlebox_synapse_client_emotiv( \
421                      log=self.log, \
422                      server_host=server_host, \
423                      server_port=server_port, \
424                      DEBUG=DEBUG, \
425                      parent=self)
426               
427                self.emotivClient.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, 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 devices)):
935                                        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 (devices)
944       
945       
946        ##################################################################
947       
948        def hcitoolGetActiveConnections(self, 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 devices)):
1006                                        devices.append(address)
1007               
1008               
1009                return (devices)
1010       
1011       
1012        ##################################################################
1013       
1014        def searchForDevices(self):
1015               
1016                enable_hcitool = configuration.ENABLE_HCITOOL
1017               
1018                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 devices)):
1055                                                        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 devices == []:
1066                                                if self.DEBUG:
1067                                                        print "INFO: No devices found through PyBluez module. Falling back to hcitool."
1068                                                devices = self.hcitoolGetActiveConnections(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                                devices = self.hcitoolScanForRemoteDevices(devices)
1084                                devices = self.hcitoolGetActiveConnections(devices)
1085                       
1086                       
1087                        if self.DEBUG > 2:
1088                                print "Bluetooth Devices found:",
1089                                print devices
1090               
1091               
1092                devices = self.searchForSerialDevices(devices)
1093               
1094               
1095                if self.DEBUG:
1096                        print "Devices found:",
1097                        print devices
1098               
1099               
1100                return(devices)
1101       
1102       
1103        ##################################################################
1104       
1105        def updateDevices(self):
1106               
1107                model = self.comboBoxEEGHeadsetModel.currentText()
1108               
1109                devices = self.searchForDevices()
1110               
1111                self.comboBoxDeviceSelect.clear()
1112               
1113                if (model == 'NeuroSky MindWave' or \
1114                    model == 'NeuroSky MindSet' or \
1115                    model == 'NeuroSky MindWave Mobile'):
1116                       
1117                        devices.insert(0, 'ThinkGear Emulator')
1118               
1119                elif (model == 'Emotiv EPOC'):
1120                       
1121                        devices.insert(0, 'Emotiv Headset')
1122                        devices.insert(0, 'EmoComposer')
1123               
1124               
1125                for device in devices:
1126                        self.comboBoxDeviceSelect.addItem(device)
1127       
1128       
1129        ##################################################################
1130       
1131        def collectData(self, source=None, target=None):
1132               
1133                if source == None:
1134                        if self.parent == None:
1135                                source = self
1136                        else:
1137                                source = self.parent
1138               
1139                if target == None:
1140                        if self.parent == None:
1141                                target = self
1142                        else:
1143                                target = self.parent
1144               
1145                data = {}
1146               
1147                data['rawEeg'] = source.packets['rawEeg']
1148                data['signals'] = source.packets['signals']
1149               
1150                data['sessionTime'] = self.calculateSessionTime()
1151               
1152                data['profileName'] = str(target.lineEditSessionProfile.text())
1153               
1154                return(data)
1155       
1156       
1157        ##################################################################
1158       
1159        def parseTimeStamp(self, timestamp, local_version=False, truncate_time_zone=False):
1160               
1161                try:
1162                        decimal = '%f' % timestamp
1163                        decimal = decimal.split('.')[1]
1164                except:
1165                        decimal = '0'
1166               
1167                localtime = time.localtime(timestamp)
1168               
1169                if local_version:
1170                        date = time.strftime('%x', localtime)
1171                        localtime = time.strftime('%X', localtime)
1172               
1173                elif truncate_time_zone:
1174                        date = time.strftime('%Y-%m-%d', localtime)
1175                        localtime = time.strftime('%H:%M:%S', localtime)
1176                        localtime = '%s.%s' % (localtime, decimal[:3])
1177               
1178                else:
1179                        date = time.strftime('%Y-%m-%d', localtime)
1180                        localtime = time.strftime('%H:%M:%S', localtime)
1181                        localtime = '%s.%s %s' % (localtime, decimal, \
1182                                       time.strftime('%Z', time.localtime(timestamp)))
1183               
1184               
1185                return(date, localtime)
1186       
1187       
1188        ##################################################################
1189       
1190        def saveData(self, source=None, target=None, output_file=None, use_default=False):
1191               
1192                if source == None:
1193                        if self.parent == None:
1194                                source = self
1195                        else:
1196                                source = self.parent
1197               
1198                if target == None:
1199                        if self.parent == None:
1200                                target = self
1201                        else:
1202                                target = self.parent
1203               
1204                data = self.collectData(source=source, target=target)
1205               
1206                (date, localtime) = self.parseTimeStamp(time.time())
1207               
1208                default_filename = '%s %s.synapse' % (date, \
1209                                      target.lineEditSessionProfile.text())
1210                                     
1211                default_filename = os.path.join(self.homepath, default_filename)
1212               
1213                if output_file == None:
1214                       
1215                        # use_default controls whether or not a file is automatically saves using the
1216                        # default name and path (as opposed to raising a GUI file selection menu)
1217                        # whenever an explicit filepath is not defined
1218                        if use_default:
1219                                       
1220                                        output_file = default_filename
1221                       
1222                        else:
1223                       
1224                                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
1225                                                 caption="Save Session Data to File", \
1226                                                 dir=default_filename, \
1227                                                 filter="Puzzlebox Synapse Data File (*.synapse)")
1228                               
1229                                try:
1230                                        output_file = output_file[0]
1231                                except:
1232                                        output_file = ''
1233               
1234               
1235                if output_file == '':
1236                        return
1237               
1238                file = open(str(output_file), 'w')
1239                pickle.dump(data, file)
1240                file.close()
1241       
1242       
1243        ##################################################################
1244       
1245        def exportData(self, parent=None, source=None, target=None, output_file=None, use_default=False):
1246               
1247                if parent == None:
1248                        if self.parent == None:
1249                                parent = self
1250                        else:
1251                                parent = self.parent
1252               
1253                if source == None:
1254                        if self.parent == None:
1255                                source = self
1256                        else:
1257                                source = self.parent
1258               
1259                if target == None:
1260                        if self.parent == None:
1261                                target = self
1262                        else:
1263                                target = self.parent
1264               
1265               
1266                (date, localtime) = self.parseTimeStamp(time.time())
1267               
1268                default_filename = '%s %s.csv' % (date, \
1269                                      target.lineEditSessionProfile.text())
1270               
1271                default_filename = os.path.join(target.homepath, default_filename)
1272               
1273               
1274                if output_file == None:
1275                       
1276                        # use_default controls whether or not a file is automatically saves using the
1277                        # default name and path (as opposed to raising a GUI file selection menu)
1278                        # whenever an explicit filepath is not defined
1279                        if use_default:
1280                                       
1281                                        output_file = default_filename
1282                       
1283                        else:
1284                                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
1285                                                 caption="Export Session Data to File", \
1286                                                 dir=default_filename, \
1287                                                 filter="CSV File (*.csv);;Text File (*.txt)")
1288                               
1289                                try:
1290                                        output_file = output_file[0]
1291                                except:
1292                                        output_file = ''
1293               
1294               
1295                if output_file == '':
1296                        return
1297               
1298               
1299                if str(output_file).endswith('.csv'):
1300                       
1301                        outputData = self.exportDataToCSV(parent=parent, source=source, target=target)
1302               
1303               
1304                else:
1305                       
1306                        try:
1307                                outputData = self.textEditDebugConsole.toPlainText()
1308                        except:
1309                                outputData = self.exportDataToCSV()
1310               
1311               
1312                file = open(str(output_file), 'w')
1313                file.write(outputData)
1314                file.close()
1315       
1316       
1317        ##################################################################
1318       
1319        def exportDataToCSV(self, parent=None, source=None, target=None):
1320               
1321                if parent == None:
1322                        if self.parent == None:
1323                                parent = self
1324                        else:
1325                                parent = self.parent
1326               
1327                if source == None:
1328                        if self.parent == None:
1329                                source = self
1330                        else:
1331                                source = self.parent
1332               
1333                if target == None:
1334                        if self.parent == None:
1335                                target = self
1336                        else:
1337                                target = self.parent
1338               
1339                try:
1340                        truncate_csv_timezone = target.configuration.EXPORT_CSV_TRUNCATE_TIMEZONE
1341                except:
1342                        truncate_csv_timezone = False
1343               
1344                try:
1345                        scrub_data = target.configuration.EXPORT_CSV_SCRUB_DATA
1346                except:
1347                        scrub_data = False
1348               
1349               
1350                headers = 'Date,Time,Attention,Meditation,Signal Level,Delta,Theta,Low Alpha,High Alpha,Low Beta,High Beta,Low Gamma,Mid Gamma'
1351               
1352                customDataHeaders = []
1353                for header in parent.customDataHeaders:
1354                        customDataHeaders.append(header)
1355                for plugin in parent.activePlugins:
1356                        for header in plugin.customDataHeaders:
1357                                customDataHeaders.append(header)
1358               
1359                for each in customDataHeaders:
1360                        headers = headers + ',%s' % each
1361               
1362                headers = headers + '\n'
1363               
1364                csv = {}
1365               
1366                for packet in source.packets['signals']:
1367                       
1368                       
1369                        if 'rawEeg' in packet.keys():
1370                                continue
1371                       
1372                        if packet['timestamp'] not in csv.keys():
1373                               
1374                                if 'blinkStrength' in packet.keys():
1375                                        # Skip any blink packets from log
1376                                        continue
1377                               
1378                               
1379                                #print packet
1380                                timestamp = packet['timestamp']
1381                                (date, localtime) = self.parseTimeStamp(timestamp, \
1382                                                    truncate_time_zone=truncate_csv_timezone)
1383                               
1384                                csv[timestamp] = {}
1385                                csv[timestamp]['Date'] = date
1386                                csv[timestamp]['Time'] = localtime
1387                                csv[timestamp]['Attention'] = ''
1388                                csv[timestamp]['Meditation'] = ''
1389                                csv[timestamp]['Signal Level'] = ''
1390                                csv[timestamp]['Delta'] = ''
1391                                csv[timestamp]['Theta'] = ''
1392                                csv[timestamp]['Low Alpha'] = ''
1393                                csv[timestamp]['High Alpha'] = ''
1394                                csv[timestamp]['Low Beta'] = ''
1395                                csv[timestamp]['High Beta'] = ''
1396                                csv[timestamp]['Low Gamma'] = ''
1397                                csv[timestamp]['Mid Gamma'] = ''
1398                               
1399                                for header in customDataHeaders:
1400                                        csv[timestamp][header] = ''
1401                       
1402                       
1403                        if 'eSense' in packet.keys():
1404                                if 'attention' in packet['eSense'].keys():
1405                                        csv[timestamp]['Attention'] = packet['eSense']['attention']
1406                                if 'meditation' in packet['eSense'].keys():
1407                                        csv[timestamp]['Meditation'] = packet['eSense']['meditation']
1408                       
1409                        if 'eegPower' in packet.keys():
1410                                if 'delta' in packet['eegPower'].keys():
1411                                        csv[timestamp]['Delta'] = packet['eegPower']['delta']
1412                                if 'theta' in packet['eegPower'].keys():
1413                                        csv[timestamp]['Theta'] = packet['eegPower']['theta']
1414                                if 'lowAlpha' in packet['eegPower'].keys():
1415                                        csv[timestamp]['Low Alpha'] = packet['eegPower']['lowAlpha']
1416                                if 'highAlpha' in packet['eegPower'].keys():
1417                                        csv[timestamp]['High Alpha'] = packet['eegPower']['highAlpha']
1418                                if 'lowBeta' in packet['eegPower'].keys():
1419                                        csv[timestamp]['Low Beta'] = packet['eegPower']['lowBeta']
1420                                if 'highBeta' in packet['eegPower'].keys():
1421                                        csv[timestamp]['High Beta'] = packet['eegPower']['highBeta']
1422                                if 'lowGamma' in packet['eegPower'].keys():
1423                                        csv[timestamp]['Low Gamma'] = packet['eegPower']['lowGamma']
1424                                if 'highGamma' in packet['eegPower'].keys():
1425                                        csv[timestamp]['Mid Gamma'] = packet['eegPower']['highGamma']
1426                       
1427                        if 'poorSignalLevel' in packet.keys():
1428                                csv[timestamp]['Signal Level'] = packet['poorSignalLevel']
1429                       
1430                        for header in customDataHeaders:
1431                                if 'custom' in packet.keys() and \
1432                                   header in packet['custom'].keys():
1433                                        csv[timestamp][header] = packet['custom'][header]
1434               
1435               
1436                if scrub_data:
1437                        csv = self.scrubData(csv, truncate_csv_timezone)
1438               
1439               
1440                output = headers
1441               
1442                csv_keys = csv.keys()
1443                csv_keys.sort()
1444               
1445                for key in csv_keys:
1446                       
1447                        row = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % \
1448                              (csv[key]['Date'], \
1449                               csv[key]['Time'], \
1450                               csv[key]['Attention'], \
1451                               csv[key]['Meditation'], \
1452                               csv[key]['Signal Level'], \
1453                               csv[key]['Delta'], \
1454                               csv[key]['Theta'], \
1455                               csv[key]['Low Alpha'], \
1456                               csv[key]['High Alpha'], \
1457                               csv[key]['Low Beta'], \
1458                               csv[key]['High Beta'], \
1459                               csv[key]['Low Gamma'], \
1460                               csv[key]['Mid Gamma'])
1461                       
1462                        for header in customDataHeaders:
1463                                row = row + ',%s' % csv[key][header]
1464                       
1465                        row = row + '\n'
1466                       
1467                        output = output + row
1468               
1469               
1470                return(output)
1471       
1472       
1473        ##################################################################
1474       
1475        def scrubData(self, csv, truncate_csv_timezone=False):
1476               
1477                # If there are missing packets, repeat a given packet once per missing
1478                # second until there is a gap between 1 and 2 seconds, in which case
1479                # produce a final duplicate packet at the mid-point between the packets
1480
1481                if self.DEBUG:
1482                        print "INFO: Scrubbing Data"
1483               
1484                last_time = None
1485                last_recorded_time = None
1486               
1487                output = {}
1488               
1489                csv_keys = csv.keys()
1490                csv_keys.sort()
1491               
1492                for key in csv_keys:
1493                       
1494                        timestamp = key
1495
1496                        if csv[key]['Attention'] == '':
1497                                continue
1498                       
1499                        if last_time == None:
1500                                # First entry in log
1501                                last_time = timestamp
1502                                last_recorded_time = timestamp
1503                                output[key] = csv[key]
1504                                continue
1505                       
1506                        else:
1507                               
1508                                #time_difference = timestamp - last_time
1509                                time_difference = timestamp - last_recorded_time
1510                               
1511                                if (time_difference <= 1) and \
1512                                   (time_difference >= PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD):
1513                                        # Skip packets within the correct time threshold
1514                                        last_time = timestamp
1515                                        last_recorded_time = timestamp
1516                                        output[key] = csv[key]
1517                                        continue
1518                               
1519                                else:
1520                                       
1521                                        if self.DEBUG > 1:
1522                                                print "time_difference:",
1523                                                print time_difference
1524                                                print "timestamp:",
1525                                                print self.parseTimeStamp(timestamp)[-1].split(' ')[0]
1526                                                print "last_time:",
1527                                                print self.parseTimeStamp(last_time)[-1].split(' ')[0]
1528                                                print "last_recorded_time:",
1529                                                print self.parseTimeStamp(last_recorded_time)[-1].split(' ')[0]
1530                                       
1531                                       
1532                                        new_packet = csv[key].copy()
1533                                       
1534                                        if time_difference >= 2:
1535                                               
1536                                                ##new_time = last_time + 1
1537                                                #new_time = last_recorded_time + 1
1538                                               
1539                                                count = int(time_difference)
1540                                                while count >= 1:
1541                                                        new_packet = csv[key].copy()
1542                                                        new_time = last_recorded_time + 1
1543                                                        (date, formatted_new_time) = self.parseTimeStamp(new_time, \
1544                                                         truncate_time_zone=truncate_csv_timezone)
1545                                                        new_packet['Time'] = formatted_new_time
1546                                                        last_recorded_time = new_time
1547                                                        last_time = timestamp
1548                                                        output[new_time] = new_packet
1549                                                        count = count - 1
1550                                                continue
1551                                               
1552                                        elif time_difference < PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD:
1553                                                # Spread out "bunched up" packets
1554                                                #new_time = last_time + 1
1555                                                new_time = last_recorded_time + 1
1556                                       
1557                                       
1558                                        elif (time_difference < 2) and (time_difference > 1):
1559                                               
1560                                                #new_time = last_time + ((last_time - timestamp) / 2)
1561                                                #new_time = last_recorded_time + ((last_recorded_time - timestamp) / 2)
1562                                                #new_time = last_time + 1
1563                                                new_time = last_recorded_time + 1
1564                                       
1565                                       
1566                                        (date, formatted_new_time) = self.parseTimeStamp(new_time, \
1567                                           truncate_time_zone=truncate_csv_timezone)
1568                                       
1569                                        new_packet['Time'] = formatted_new_time
1570                                       
1571                                        #last_time = new_time
1572                                        last_recorded_time = new_time
1573                                        last_time = timestamp
1574                                        output[new_time] = new_packet
1575                                       
1576                                        if self.DEBUG > 1:
1577                                                print "WARN: Scrubbing new packet:",
1578                                                print new_packet
1579                                                print
1580               
1581               
1582                return(output)
1583       
1584       
1585        ##################################################################
1586       
1587        def resetData(self, source=None):
1588               
1589                if source == None:
1590                        if self.parent == None:
1591                                source = self
1592                        else:
1593                                source = self.parent
1594               
1595                #if target == None:
1596                        #if self.parent == None:
1597                                #target = self
1598                        #else:
1599                                #target = self.parent
1600               
1601                source.packets['rawEeg'] = []
1602                source.packets['signals'] = []
1603               
1604                source.thinkGearConnectServer.protocol.session_start_timestamp = \
1605                        time.time()
1606               
1607                source.thinkGearConnectServer.protocol.packet_count = 0
1608                source.thinkGearConnectServer.protocol.bad_packets = 0
1609               
1610                self.updateProfileSessionStatus()
1611               
1612                try:
1613                        source.textEditDebugConsole.setText("")
1614                except:
1615                        pass
1616       
1617       
1618        #####################################################################
1619       
1620        def convert_seconds_to_datetime(self, duration):
1621               
1622                duration_hours = duration / (60 * 60)
1623                duration_minutes = (duration - (duration_hours * (60 * 60))) / 60
1624                duration_seconds = (duration - (duration_hours * (60 * 60)) - (duration_minutes * 60))
1625               
1626                duration_hours = '%i' % duration_hours
1627                if (len(duration_hours) == 1):
1628                        duration_hours = "0%s" % duration_hours
1629               
1630                duration_minutes = '%i' % duration_minutes
1631                if (len(duration_minutes) == 1):
1632                        duration_minutes = "0%s" % duration_minutes
1633               
1634                duration_seconds = '%i' % duration_seconds
1635                if (len(duration_seconds) == 1):
1636                        duration_seconds = "0%s" % duration_seconds
1637               
1638                datetime = '%s:%s:%s' % (duration_hours, duration_minutes, duration_seconds)
1639               
1640                return(datetime)
1641       
1642       
1643        ##################################################################
1644       
1645        def stop(self):
1646               
1647                if UPDATE_INTERFACE_VIA_TIMER:
1648                        self.updateInterfaceTimer.stop()
1649                else:
1650                        if self.thinkgearConnectClient != None:
1651                                self.thinkgearConnectClient.exitThread()
1652               
1653                if self.thinkGearConnectServer != None:
1654                        self.thinkGearConnectServer.exitThread()
1655       
1656       
1657        ##################################################################
1658       
1659        def closeEvent(self, event):
1660               
1661                quit_message = "Are you sure you want to exit the program?"
1662               
1663                reply = QtGui.QMessageBox.question( \
1664                           self, \
1665                          'Message', \
1666                           quit_message, \
1667                           QtGui.QMessageBox.Yes, \
1668                           QtGui.QMessageBox.No)
1669               
1670                if reply == QtGui.QMessageBox.Yes:
1671                       
1672                        self.stop()
1673                       
1674                        event.accept()
1675               
1676                else:
1677                        event.ignore()
Note: See TracBrowser for help on using the repository browser.