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

Last change on this file since 285 was 285, checked in by sc, 11 years ago

Interface:

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