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

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

Interface:

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