source: trunk/Puzzlebox/Synapse/Session.py @ 382

Last change on this file since 382 was 382, checked in by sc, 8 years ago

Session:

  • debug enhancement
File size: 17.2 KB
Line 
1# -*- coding: utf-8 -*-
2
3# Copyright Puzzlebox Productions, LLC (2010-2012)
4#
5# This code is released under the GNU Pulic License (GPL) version 2
6# For more information please refer to http://www.gnu.org/copyleft/gpl.html
7
8__changelog__ = """\
9Last Update: 2012.04.01
10"""
11
12__todo__ = """
13"""
14
15### IMPORTS ###
16import os, sys, time
17
18import Puzzlebox.Synapse.Configuration as configuration
19
20if configuration.ENABLE_PYSIDE:
21        try:
22                import PySide as PyQt4
23                from PySide import QtCore, QtGui
24        except Exception, e:
25                print "ERROR: [Synapse:Session] Exception importing PySide:",
26                print e
27                configuration.ENABLE_PYSIDE = False
28        else:
29                print "INFO: [Synapse:Session] Using PySide module"
30
31if not configuration.ENABLE_PYSIDE:
32        print "INFO: [Synapse:Session] Using PyQt4 module"
33        from PyQt4 import QtCore, QtGui
34
35
36try:
37        import cPickle as pickle
38except:
39        import pickle
40
41
42#####################################################################
43# Globals
44#####################################################################
45
46DEBUG = configuration.DEBUG
47
48PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD = 0.75
49
50
51#####################################################################
52# Classes
53#####################################################################
54
55class puzzlebox_synapse_session(QtGui.QWidget):
56       
57        def __init__(self, log, \
58                     DEBUG=DEBUG, \
59                     parent=None, \
60                     ):
61               
62                self.log = log
63                self.DEBUG = DEBUG
64                self.parent=parent
65               
66                if self.parent == None:
67                        QtGui.QWidget.__init__(self, parent)
68                        #self.setupUi(self)
69               
70                        self.configureSettings()
71                        self.connectWidgets()
72               
73                self.name = "Synapse:Session"
74               
75               
76                if (sys.platform == 'win32'):
77                        self.homepath = os.path.join( \
78                           os.environ['HOMEDRIVE'], \
79                           os.environ['HOMEPATH'], \
80                           'Desktop')
81                elif (sys.platform == 'darwin'):
82                        desktop = os.path.join(os.environ['HOME'], 'Documents')
83                        if os.path.exists(desktop):
84                                self.homepath = desktop
85                        else:
86                                self.homepath = os.environ['HOME']
87                else:
88                        desktop = os.path.join(os.environ['HOME'], 'Desktop')
89                        if os.path.exists(desktop):
90                                self.homepath = desktop
91                        else:
92                                self.homepath = os.environ['HOME']
93               
94               
95                if not os.path.exists(self.homepath):
96                        if self.DEBUG:
97                                print "WARNING: [Synapse:Session] User default path not found"
98                        self.homepath = os.getcwd()
99       
100       
101        ##################################################################
102       
103        def configureSettings(self):
104               
105                pass
106       
107       
108        ##################################################################
109       
110        def connectWidgets(self):
111               
112                pass
113       
114       
115        ##################################################################
116       
117        def updateProfileSessionStatus(self, source=None, target=None):
118               
119                session_time = self.calculateSessionTime()
120               
121                #if source == None:
122                        #if self.parent == None:
123                                #source = self
124                        #else:
125                                #source = self.parent
126               
127                #if target == None:
128                        #if self.parent == None:
129                                #target = self
130                        #else:
131                                #target = self.parent
132               
133                #target.textLabelSessionTime.setText(session_time)
134                self.textLabelSessionTime.setText(session_time)
135               
136                try:
137                        #target.textLabelPacketsReceived.setText( "%i" % \
138                                #source.synapseServer.protocol.packet_count)
139                        self.textLabelPacketsReceived.setText( "%i" % \
140                                self.synapseServer.protocol.packet_count)
141                except:
142                        pass
143               
144                try:
145                        #target.textLabelPacketsDropped.setText( "%i" % \
146                                #source.synapseServer.protocol.bad_packets)
147                        self.textLabelPacketsDropped.setText( "%i" % \
148                                self.synapseServer.protocol.bad_packets)
149                except:
150                        pass
151       
152       
153        ##################################################################
154       
155        def calculateSessionTime(self):
156               
157                #if self.parent == None:
158                        #server = self.synapseServer
159                #else:
160                        #server = self.parent.synapseServer
161               
162                session_time = time.time() - \
163                        self.synapseServer.session_start_timestamp
164                        #server.session_start_timestamp
165                        #server.protocol.session_start_timestamp
166               
167                session_time = int(session_time)
168               
169                session_time = self.convert_seconds_to_datetime(session_time)
170               
171                return(session_time)
172       
173       
174        ##################################################################
175       
176        def collectData(self, source=None, target=None):
177               
178                if source == None:
179                        if self.parent == None:
180                                source = self
181                        else:
182                                source = self.parent
183               
184                if target == None:
185                        if self.parent == None:
186                                target = self
187                        else:
188                                target = self.parent
189               
190                data = {}
191               
192                data['rawEeg'] = source.packets['rawEeg']
193                data['signals'] = source.packets['signals']
194               
195                data['sessionTime'] = self.calculateSessionTime()
196               
197                data['profileName'] = str(target.lineEditSessionProfile.text())
198               
199                return(data)
200       
201       
202        ##################################################################
203       
204        def parseTimeStamp(self, timestamp, local_version=False, truncate_time_zone=False):
205               
206                try:
207                        decimal = '%f' % timestamp
208                        decimal = decimal.split('.')[1]
209                except:
210                        decimal = '0'
211               
212                localtime = time.localtime(timestamp)
213               
214                if local_version:
215                        date = time.strftime('%x', localtime)
216                        localtime = time.strftime('%X', localtime)
217               
218                elif truncate_time_zone:
219                        date = time.strftime('%Y-%m-%d', localtime)
220                        localtime = time.strftime('%H:%M:%S', localtime)
221                        localtime = '%s.%s' % (localtime, decimal[:3])
222               
223                else:
224                        date = time.strftime('%Y-%m-%d', localtime)
225                        localtime = time.strftime('%H:%M:%S', localtime)
226                        localtime = '%s.%s %s' % (localtime, decimal, \
227                                       time.strftime('%Z', time.localtime(timestamp)))
228               
229               
230                return(date, localtime)
231       
232       
233        ##################################################################
234       
235        def saveData(self, source=None, target=None, output_file=None, use_default=False):
236               
237                if source == None:
238                        if self.parent == None:
239                                source = self
240                        else:
241                                source = self.parent
242               
243                if target == None:
244                        if self.parent == None:
245                                target = self
246                        else:
247                                target = self.parent
248               
249                data = self.collectData(source=source, target=target)
250               
251                (date, localtime) = self.parseTimeStamp(time.time())
252               
253                default_filename = '%s %s.synapse' % (date, \
254                                      target.lineEditSessionProfile.text())
255                                     
256                default_filename = os.path.join(self.homepath, default_filename)
257               
258                if output_file == None:
259                       
260                        # use_default controls whether or not a file is automatically saves using the
261                        # default name and path (as opposed to raising a GUI file selection menu)
262                        # whenever an explicit filepath is not defined
263                        if use_default:
264                                       
265                                        output_file = default_filename
266                       
267                        else:
268                       
269                                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
270                                                 caption="Save Session Data to File", \
271                                                 dir=default_filename, \
272                                                 filter="Puzzlebox Synapse Data File (*.synapse)")
273                               
274                                try:
275                                        output_file = output_file[0]
276                                except:
277                                        output_file = ''
278               
279               
280                if output_file == '':
281                        return
282               
283                file = open(str(output_file), 'w')
284                pickle.dump(data, file)
285                file.close()
286       
287       
288        ##################################################################
289       
290        def exportData(self, parent=None, source=None, target=None, output_file=None, use_default=False):
291               
292                if parent == None:
293                        if self.parent == None:
294                                parent = self
295                        else:
296                                parent = self.parent
297               
298                if source == None:
299                        if self.parent == None:
300                                source = self
301                        else:
302                                source = self.parent
303               
304                if target == None:
305                        if self.parent == None:
306                                target = self
307                        else:
308                                target = self.parent
309               
310               
311                (date, localtime) = self.parseTimeStamp(time.time())
312               
313                default_filename = '%s %s.csv' % (date, \
314                                      target.lineEditSessionProfile.text())
315               
316                default_filename = os.path.join(target.homepath, default_filename)
317               
318               
319                if output_file == None:
320                       
321                        # use_default controls whether or not a file is automatically saves using the
322                        # default name and path (as opposed to raising a GUI file selection menu)
323                        # whenever an explicit filepath is not defined
324                        if use_default:
325                                       
326                                        output_file = default_filename
327                       
328                        else:
329                                output_file = QtGui.QFileDialog.getSaveFileName(parent=target, \
330                                                 caption="Export Session Data to File", \
331                                                 dir=default_filename, \
332                                                 filter="CSV File (*.csv);;Text File (*.txt)")
333                               
334                                try:
335                                        output_file = output_file[0]
336                                except:
337                                        output_file = ''
338               
339               
340                if output_file == '':
341                        return
342               
343               
344                if str(output_file).endswith('.csv'):
345                       
346                        outputData = self.exportDataToCSV(parent=parent, source=source, target=target)
347               
348               
349                else:
350                       
351                        try:
352                                outputData = self.textEditDebugConsole.toPlainText()
353                        except:
354                                outputData = self.exportDataToCSV()
355               
356               
357                file = open(str(output_file), 'w')
358                file.write(outputData)
359                file.close()
360       
361       
362        ##################################################################
363       
364        def exportDataToCSV(self, parent=None, source=None, target=None):
365               
366                if parent == None:
367                        if self.parent == None:
368                                parent = self
369                        else:
370                                parent = self.parent
371               
372                if source == None:
373                        if self.parent == None:
374                                source = self
375                        else:
376                                source = self.parent
377               
378                if target == None:
379                        if self.parent == None:
380                                target = self
381                        else:
382                                target = self.parent
383               
384                try:
385                        truncate_csv_timezone = target.configuration.EXPORT_CSV_TRUNCATE_TIMEZONE
386                except:
387                        truncate_csv_timezone = False
388               
389                try:
390                        scrub_data = target.configuration.EXPORT_CSV_SCRUB_DATA
391                except:
392                        scrub_data = False
393               
394               
395                headers = 'Date,Time,Attention,Meditation,Signal Level,Delta,Theta,Low Alpha,High Alpha,Low Beta,High Beta,Low Gamma,Mid Gamma'
396               
397                customDataHeaders = []
398                for header in parent.customDataHeaders:
399                        customDataHeaders.append(header)
400                for plugin in parent.activePlugins:
401                        for header in plugin.customDataHeaders:
402                                customDataHeaders.append(header)
403               
404                for each in customDataHeaders:
405                        headers = headers + ',%s' % each
406               
407                headers = headers + '\n'
408               
409                csv = {}
410               
411                for packet in source.packets['signals']:
412                       
413                       
414                        if 'rawEeg' in packet.keys():
415                                continue
416                       
417                        if packet['timestamp'] not in csv.keys():
418                               
419                                if 'blinkStrength' in packet.keys():
420                                        # Skip any blink packets from log
421                                        continue
422                               
423                               
424                                #print packet
425                                timestamp = packet['timestamp']
426                                (date, localtime) = self.parseTimeStamp(timestamp, \
427                                                    truncate_time_zone=truncate_csv_timezone)
428                               
429                                csv[timestamp] = {}
430                                csv[timestamp]['Date'] = date
431                                csv[timestamp]['Time'] = localtime
432                                csv[timestamp]['Attention'] = ''
433                                csv[timestamp]['Meditation'] = ''
434                                csv[timestamp]['Signal Level'] = ''
435                                csv[timestamp]['Delta'] = ''
436                                csv[timestamp]['Theta'] = ''
437                                csv[timestamp]['Low Alpha'] = ''
438                                csv[timestamp]['High Alpha'] = ''
439                                csv[timestamp]['Low Beta'] = ''
440                                csv[timestamp]['High Beta'] = ''
441                                csv[timestamp]['Low Gamma'] = ''
442                                csv[timestamp]['Mid Gamma'] = ''
443                               
444                                for header in customDataHeaders:
445                                        csv[timestamp][header] = ''
446                       
447                       
448                        if 'eSense' in packet.keys():
449                                if 'attention' in packet['eSense'].keys():
450                                        csv[timestamp]['Attention'] = packet['eSense']['attention']
451                                if 'meditation' in packet['eSense'].keys():
452                                        csv[timestamp]['Meditation'] = packet['eSense']['meditation']
453                       
454                        if 'eegPower' in packet.keys():
455                                if 'delta' in packet['eegPower'].keys():
456                                        csv[timestamp]['Delta'] = packet['eegPower']['delta']
457                                if 'theta' in packet['eegPower'].keys():
458                                        csv[timestamp]['Theta'] = packet['eegPower']['theta']
459                                if 'lowAlpha' in packet['eegPower'].keys():
460                                        csv[timestamp]['Low Alpha'] = packet['eegPower']['lowAlpha']
461                                if 'highAlpha' in packet['eegPower'].keys():
462                                        csv[timestamp]['High Alpha'] = packet['eegPower']['highAlpha']
463                                if 'lowBeta' in packet['eegPower'].keys():
464                                        csv[timestamp]['Low Beta'] = packet['eegPower']['lowBeta']
465                                if 'highBeta' in packet['eegPower'].keys():
466                                        csv[timestamp]['High Beta'] = packet['eegPower']['highBeta']
467                                if 'lowGamma' in packet['eegPower'].keys():
468                                        csv[timestamp]['Low Gamma'] = packet['eegPower']['lowGamma']
469                                if 'highGamma' in packet['eegPower'].keys():
470                                        csv[timestamp]['Mid Gamma'] = packet['eegPower']['highGamma']
471                       
472                        if 'poorSignalLevel' in packet.keys():
473                                csv[timestamp]['Signal Level'] = packet['poorSignalLevel']
474                       
475                        for header in customDataHeaders:
476                                if 'custom' in packet.keys() and \
477                                   header in packet['custom'].keys():
478                                        csv[timestamp][header] = packet['custom'][header]
479               
480               
481                if scrub_data:
482                        csv = self.scrubData(csv, truncate_csv_timezone)
483               
484               
485                output = headers
486               
487                csv_keys = csv.keys()
488                csv_keys.sort()
489               
490                for key in csv_keys:
491                       
492                        row = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % \
493                              (csv[key]['Date'], \
494                               csv[key]['Time'], \
495                               csv[key]['Attention'], \
496                               csv[key]['Meditation'], \
497                               csv[key]['Signal Level'], \
498                               csv[key]['Delta'], \
499                               csv[key]['Theta'], \
500                               csv[key]['Low Alpha'], \
501                               csv[key]['High Alpha'], \
502                               csv[key]['Low Beta'], \
503                               csv[key]['High Beta'], \
504                               csv[key]['Low Gamma'], \
505                               csv[key]['Mid Gamma'])
506                       
507                        for header in customDataHeaders:
508                                row = row + ',%s' % csv[key][header]
509                       
510                        row = row + '\n'
511                       
512                        output = output + row
513               
514               
515                return(output)
516       
517       
518        ##################################################################
519       
520        def scrubData(self, csv, truncate_csv_timezone=False):
521               
522                # If there are missing packets, repeat a given packet once per missing
523                # second until there is a gap between 1 and 2 seconds, in which case
524                # produce a final duplicate packet at the mid-point between the packets
525
526                if self.DEBUG:
527                        print "INFO: Scrubbing Data"
528               
529                last_time = None
530                last_recorded_time = None
531               
532                output = {}
533               
534                csv_keys = csv.keys()
535                csv_keys.sort()
536               
537                for key in csv_keys:
538                       
539                        timestamp = key
540
541                        if csv[key]['Attention'] == '':
542                                continue
543                       
544                        if last_time == None:
545                                # First entry in log
546                                last_time = timestamp
547                                last_recorded_time = timestamp
548                                output[key] = csv[key]
549                                continue
550                       
551                        else:
552                               
553                                #time_difference = timestamp - last_time
554                                time_difference = timestamp - last_recorded_time
555                               
556                                if (time_difference <= 1) and \
557                                   (time_difference >= PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD):
558                                        # Skip packets within the correct time threshold
559                                        last_time = timestamp
560                                        last_recorded_time = timestamp
561                                        output[key] = csv[key]
562                                        continue
563                               
564                                else:
565                                       
566                                        if self.DEBUG > 1:
567                                                print "time_difference:",
568                                                print time_difference
569                                                print "timestamp:",
570                                                print self.parseTimeStamp(timestamp)[-1].split(' ')[0]
571                                                print "last_time:",
572                                                print self.parseTimeStamp(last_time)[-1].split(' ')[0]
573                                                print "last_recorded_time:",
574                                                print self.parseTimeStamp(last_recorded_time)[-1].split(' ')[0]
575                                       
576                                       
577                                        new_packet = csv[key].copy()
578                                       
579                                        if time_difference >= 2:
580                                               
581                                                ##new_time = last_time + 1
582                                                #new_time = last_recorded_time + 1
583                                               
584                                                count = int(time_difference)
585                                                while count >= 1:
586                                                        new_packet = csv[key].copy()
587                                                        new_time = last_recorded_time + 1
588                                                        (date, formatted_new_time) = self.parseTimeStamp(new_time, \
589                                                         truncate_time_zone=truncate_csv_timezone)
590                                                        new_packet['Time'] = formatted_new_time
591                                                        last_recorded_time = new_time
592                                                        last_time = timestamp
593                                                        output[new_time] = new_packet
594                                                        count = count - 1
595                                                continue
596                                               
597                                        elif time_difference < PACKET_MINIMUM_TIME_DIFFERENCE_THRESHOLD:
598                                                # Spread out "bunched up" packets
599                                                #new_time = last_time + 1
600                                                new_time = last_recorded_time + 1
601                                       
602                                       
603                                        elif (time_difference < 2) and (time_difference > 1):
604                                               
605                                                #new_time = last_time + ((last_time - timestamp) / 2)
606                                                #new_time = last_recorded_time + ((last_recorded_time - timestamp) / 2)
607                                                #new_time = last_time + 1
608                                                new_time = last_recorded_time + 1
609                                       
610                                       
611                                        (date, formatted_new_time) = self.parseTimeStamp(new_time, \
612                                           truncate_time_zone=truncate_csv_timezone)
613                                       
614                                        new_packet['Time'] = formatted_new_time
615                                       
616                                        #last_time = new_time
617                                        last_recorded_time = new_time
618                                        last_time = timestamp
619                                        output[new_time] = new_packet
620                                       
621                                        if self.DEBUG > 1:
622                                                print "WARN: Scrubbing new packet:",
623                                                print new_packet
624                                                print
625               
626               
627                return(output)
628       
629       
630        ##################################################################
631       
632        def resetData(self, source=None):
633               
634                if source == None:
635                        if self.parent == None:
636                                source = self
637                        else:
638                                source = self.parent
639               
640                source.packets['rawEeg'] = []
641                source.packets['signals'] = []
642               
643                #source.synapseServer.protocol.session_start_timestamp = \
644                        #time.time()
645                self.synapseServer.protocol.resetSessionStartTime()
646               
647                source.synapseServer.protocol.packet_count = 0
648                source.synapseServer.protocol.bad_packets = 0
649               
650                self.updateProfileSessionStatus()
651               
652                try:
653                        source.textEditDebugConsole.setText("")
654                except:
655                        pass
656       
657       
658        #####################################################################
659       
660        def convert_seconds_to_datetime(self, duration):
661               
662                duration_hours = duration / (60 * 60)
663                duration_minutes = (duration - (duration_hours * (60 * 60))) / 60
664                duration_seconds = (duration - (duration_hours * (60 * 60)) - (duration_minutes * 60))
665               
666                duration_hours = '%i' % duration_hours
667                if (len(duration_hours) == 1):
668                        duration_hours = "0%s" % duration_hours
669               
670                duration_minutes = '%i' % duration_minutes
671                if (len(duration_minutes) == 1):
672                        duration_minutes = "0%s" % duration_minutes
673               
674                duration_seconds = '%i' % duration_seconds
675                if (len(duration_seconds) == 1):
676                        duration_seconds = "0%s" % duration_seconds
677               
678                datetime = '%s:%s:%s' % (duration_hours, duration_minutes, duration_seconds)
679               
680                return(datetime)
681
Note: See TracBrowser for help on using the repository browser.