source: trunk/Puzzlebox/Synapse/Emotiv/Server.py @ 388

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

Emotiv_Server:

  • fix to CSV header output
File size: 17.8 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.09
10"""
11
12### IMPORTS ###
13
14import os, sys, time
15import math
16
17import simplejson as json
18
19import Puzzlebox.Synapse.Configuration as configuration
20
21if configuration.ENABLE_PYSIDE:
22        try:
23                import PySide as PyQt4
24                from PySide import QtCore, QtGui, QtNetwork
25        except Exception, e:
26                print "ERROR: Exception importing PySide:",
27                print e
28                configuration.ENABLE_PYSIDE = False
29        else:
30                print "INFO: [Synapse:Emotiv:Server] Using PySide module"
31
32if not configuration.ENABLE_PYSIDE:
33        print "INFO: [Synapse:Emotiv:Server] Using PyQt4 module"
34        from PyQt4 import QtCore, QtGui, QtNetwork
35
36import Puzzlebox.Synapse.Server as synapse_server
37import Puzzlebox.Synapse.ThinkGear.Server as thinkgear_server
38import Puzzlebox.Synapse.Emotiv.Client as emotiv_client
39try:
40        import Puzzlebox.Synapse.Emotiv.Protocol as emotiv_protocol
41except Exception, e:
42        print "ERROR: [Synapse:Emotiv:Server] Exception importing Emotiv.Protocol:",
43        print e
44        emotiv_protocol = None
45
46#####################################################################
47# Globals
48#####################################################################
49
50DEBUG = configuration.DEBUG
51
52COMMUNICATION_MODE = 'Emit Signal'
53#COMMUNICATION_MODE = 'Call Parent'
54
55SERVER_INTERFACE = configuration.EMOTIV_SERVER_HOST
56SERVER_PORT = configuration.EMOTIV_SERVER_PORT_CONTROL_PANEL
57#SERVER_PORT = configuration.EMOTIV_SERVER_PORT_EMOCOMPOSER
58DEFAULT_DEVICE_MODEL = 'Emotiv EPOC'
59#THINKGEAR_DEVICE_SERIAL_PORT = configuration.THINKGEAR_DEVICE_SERIAL_PORT
60
61EMULATE_THINKGEAR_FOR_EMOTIV = configuration.EMULATE_THINKGEAR_FOR_EMOTIV
62
63CLIENT_NO_REPLY_WAIT = configuration.CLIENT_NO_REPLY_WAIT * 1000
64
65FLASH_POLICY_FILE_REQUEST = configuration.FLASH_POLICY_FILE_REQUEST
66FLASH_SOCKET_POLICY_FILE = configuration.FLASH_SOCKET_POLICY_FILE
67
68DELIMITER = configuration.SYNAPSE_DELIMITER
69
70MESSAGE_FREQUENCY_TIMER = 1 * 1000 # 1 Hz (1000 ms)
71
72ENABLE_SIMULATE_HEADSET_DATA = configuration.THINKGEAR_ENABLE_SIMULATE_HEADSET_DATA
73
74#BLINK_FREQUENCY_TIMER = configuration.THINKGEAR_BLINK_FREQUENCY_TIMER
75
76#DEFAULT_SAMPLE_WAVELENGTH = configuration.THINKGEAR_DEFAULT_SAMPLE_WAVELENGTH
77
78#THINKGEAR_ATTENTION_MULTIPLIER = configuration.THINKGEAR_ATTENTION_MULTIPLIER
79#THINKGEAR_MEDITATION_MULTIPLIER = configuration.THINKGEAR_MEDITATION_MULTIPLIER
80
81#THINKGEAR_EEG_POWER_MULTIPLIERS = configuration.THINKGEAR_EEG_POWER_MULTIPLIERS
82
83DEFAULT_AUTHORIZATION_MESSAGE = \
84        {"isAuthorized": True}
85                # Tells the client whether the server has authorized
86                # access to the user's headset data. The value is
87                # either true or false.
88
89#DEFAULT_SIGNAL_LEVEL_MESSAGE = \
90        #{"poorSignalLevel": 0}
91                ## A quantifier of the quality of the brainwave signal.
92                ## This is an integer value that is generally in the
93                ## range of 0 to 200, with 0 indicating a
94                ## good signal and 200 indicating an off-head state.
95
96#DEFAULT_EEG_POWER_MESSAGE = \
97        #{"eegPower": { \
98                #'delta': 0, \
99                #'theta': 0, \
100                #'lowAlpha': 0, \
101                #'highAlpha': 0, \
102                #'lowBeta': 0, \
103                #'highBeta': 0, \
104                #'lowGamma': 0, \
105                #'highGamma': 0, \
106                #}, \
107        #} # A container for the EEG powers. These may
108          ## be either integer or floating-point values.
109          ## Maximum values are undocumented but assumed to be 65535
110
111#DEFAULT_ESENSE_MESSAGE = \
112        #{"eSense": { \
113                #'attention': 0, \
114                #'meditation': 0, \
115                #}, \
116        #} # A container for the eSense™ attributes.
117          ## These are integer values between 0 and 100,
118          ## where 0 is perceived as a lack of that attribute
119          ## and 100 is an excess of that attribute.
120
121DEFAULT_BLINK_MESSAGE = {"blinkStrength": 255}
122        # The strength of a detected blink. This is
123        # an integer in the range of 0-255.
124
125#DEFAULT_RAWEEG_MESSAGE = {"rawEeg": 255}
126        ## The raw data reading off the forehead sensor.
127        ## This may be either an integer or a floating-point value.
128
129DEFAULT_PACKET = {}
130#DEFAULT_PACKET.update(DEFAULT_EEG_POWER_MESSAGE)
131#DEFAULT_PACKET.update(DEFAULT_SIGNAL_LEVEL_MESSAGE)
132#DEFAULT_PACKET.update(DEFAULT_ESENSE_MESSAGE)
133
134#DEFAULT_RESPONSE_MESSAGE = DEFAULT_SIGNAL_LEVEL_MESSAGE
135DEFAULT_RESPONSE_MESSAGE = DEFAULT_PACKET
136
137#####################################################################
138# Classes
139#####################################################################
140
141class puzzlebox_synapse_server_emotiv(thinkgear_server.puzzlebox_synapse_server_thinkgear):
142       
143        def __init__(self, log, \
144                          server_interface=SERVER_INTERFACE, \
145                          server_port=SERVER_PORT, \
146                          device_model=None, \
147                          device_address=SERVER_PORT, \
148                          emulate_headset_data=ENABLE_SIMULATE_HEADSET_DATA, \
149                          emulate_thinkgear=EMULATE_THINKGEAR_FOR_EMOTIV, \
150                          DEBUG=DEBUG, \
151                          parent=None):
152               
153                QtCore.QThread.__init__(self,parent)
154               
155                self.log = log
156                self.DEBUG = DEBUG
157                self.parent = parent
158               
159                self.server_interface = server_interface
160                self.server_port = server_port
161                self.device_address = device_address
162                self.device_model = device_model
163                self.emulate_headset_data = emulate_headset_data
164                self.emulate_thinkgear = emulate_thinkgear
165               
166                self.name = 'Synapse:Emotiv:Server'
167               
168                self.connection_timestamp = time.time()
169                self.session_start_timestamp = time.time()
170               
171                self.connections = []
172                self.packet_queue = []
173               
174                #self.serial_device = None
175                self.protocol = None
176               
177                self.connect(self, \
178                             QtCore.SIGNAL("sendPacket()"), \
179                             self.sendPacketQueue)
180               
181                self.message_frequency_timer = MESSAGE_FREQUENCY_TIMER
182                #self.blink_frequency_timer = BLINK_FREQUENCY_TIMER
183                #self.blink_timestamp = time.time()
184               
185               
186                self.configureEEG()
187               
188                self.configureNetwork()
189               
190               
191                #if (self.emulate_headset_data):
192                        #self.emulationTimer = QtCore.QTimer()
193                        #QtCore.QObject.connect(self.emulationTimer, \
194                                                    #QtCore.SIGNAL("timeout()"), \
195                                                    #self.emulationEvent)
196                        #self.emulationTimer.start(MESSAGE_FREQUENCY_TIMER)
197       
198       
199        ##################################################################
200       
201        def configureEEG(self):
202               
203                if self.server_interface == '*':
204                        self.server_interface = '127.0.0.1'
205               
206                if emotiv_protocol != None:
207               
208                        # We call Emotiv.Client as Emotiv.Protocol in order
209                        # to run in a separate from Emotiv.Server
210                        #self.emotivClient = \
211                        self.protocol = \
212                           emotiv_client.puzzlebox_synapse_client_emotiv( \
213                              log=self.log, \
214                              server_host=self.server_interface, \
215                              server_port=self.device_address, \
216                              DEBUG=DEBUG, \
217                              parent=self)
218                       
219                        #self.emotivClient.start()
220                        self.protocol.start()
221               
222               
223                        #emotiv_protocol.start(host=self.server_interface, \
224                                              #port=self.server_port, \
225                                              #initialized=False, \
226                                              #parent=self)
227       
228       
229        ##################################################################
230       
231        def processPacketEmotiv(self, packet):
232               
233                if self.DEBUG > 2:
234                        print packet
235               
236               
237                if self.emulate_thinkgear:
238                        packet = self.emulateThinkGear(packet)
239               
240               
241                if (packet != {}):
242                        self.packet_queue.append(packet)
243                       
244                        if COMMUNICATION_MODE == 'Emit Signal':
245                                self.emitSendPacketSignal()
246                       
247                        else:
248                                self.sendPacketQueue()
249                               
250                                if (self.parent != None):
251                                        #self.parent.processPacketEmotiv(packet)
252                                        self.parent.processPacketEEG(packet)
253       
254       
255        ##################################################################
256       
257        def emulateThinkGear(self, packet):
258               
259                if ('emotivStatus' in packet.keys()):
260                       
261                        if ('contactNumberOfQualityChannels' in packet['emotivStatus']):
262                               
263                                #poorSignalLevel = packet['emotivStatus']['wireless']
264                                packet['poorSignalLevel'] = \
265                                   (packet['emotivStatus']['contactNumberOfQualityChannels'] / 18.0) * 200
266                                packet['poorSignalLevel'] = 200 - int(packet['poorSignalLevel'])
267               
268               
269                if ('expressiv' in packet.keys()):
270                       
271                        if self.DEBUG > 2:
272                                print "INFO [Synapse:Emotiv:Server] packet['expressiv']['currentAction']",
273                                print packet['expressiv']['currentAction']
274                       
275                        if ('currentAction' in packet['expressiv'].keys()):
276                                if (packet['expressiv']['currentAction'] == 0x0002):
277                                        packet['blinkStrength'] = 255
278               
279               
280                if ('affectiv' in packet.keys()):
281                       
282                        packet['eSense'] = {}
283                       
284                        if ('excitement' in packet['affectiv'].keys()):
285                                packet['eSense']['attention'] = int(packet['affectiv']['excitement'] * 100)
286                        elif ('engagementBoredom' in packet['affectiv'].keys()):
287                                packet['eSense']['attention'] = int(packet['affectiv']['engagementBoredom'] * 100)
288                       
289                        if ('meditation' in packet['affectiv'].keys()):
290                                packet['eSense']['meditation'] = int(packet['affectiv']['meditation'] * 100)
291               
292               
293                return(packet)
294       
295       
296        ##################################################################
297       
298        def resetDevice(self):
299               
300                #if self.serial_device != None:
301                        #self.serial_device.exitThread()
302               
303                if self.protocol != None:
304                        #self.protocol.exitThread()
305                        self.stopEmotivProtocol()
306               
307                self.configureEEG()
308       
309       
310        ##################################################################
311       
312        def exportDataToCSV(self, parent=None, source=None, target=None):
313               
314                if parent == None:
315                        if self.parent == None:
316                                parent = self
317                        else:
318                                parent = self.parent
319               
320                if source == None:
321                        if self.parent == None:
322                                source = self
323                        else:
324                                source = self.parent
325               
326                if target == None:
327                        if self.parent == None:
328                                target = self
329                        else:
330                                target = self.parent
331               
332                try:
333                        truncate_csv_timezone = target.configuration.EXPORT_CSV_TRUNCATE_TIMEZONE
334                except:
335                        truncate_csv_timezone = False
336               
337                try:
338                        scrub_data = target.configuration.EXPORT_CSV_SCRUB_DATA
339                except:
340                        scrub_data = False
341               
342               
343                headers = 'Date,Time'
344                headers = headers + ','
345                #headers = headers + 'Time From Start,Headset On,Contact Number Of Quality Channels,Wireless,Excitement,Long Term Excitement,Meditation,Frustration,Engagement/Boredom,Cognitiv Action,Cognitiv Action Power'
346                headers = headers + 'Time From Start,Headset On,Contact Number Of Quality Channels,Wireless,Expressiv Action,Excitement,Long Term Excitement,Meditation,Frustration,Engagement/Boredom,Cognitiv Action,Cognitiv Action Power'
347               
348                if self.emulate_thinkgear:
349                        headers = headers + ','
350                        #headers = headers + 'Attention,Meditation,Signal Level,Delta,Theta,Low Alpha,High Alpha,Low Beta,High Beta,Low Gamma,Mid Gamma'
351                        headers = headers + 'Attention,Meditation,Signal Level'
352               
353               
354                customDataHeaders = []
355                for header in parent.customDataHeaders:
356                        customDataHeaders.append(header)
357                for plugin in parent.activePlugins:
358                        for header in plugin.customDataHeaders:
359                                customDataHeaders.append(header)
360               
361                for each in customDataHeaders:
362                        headers = headers + ',%s' % each
363               
364                headers = headers + '\n'
365               
366               
367                csv = {}
368               
369                for packet in source.packets['signals']:
370                       
371                        if 'rawEeg' in packet.keys():
372                                continue
373                       
374                        if packet['timestamp'] not in csv.keys():
375                               
376                                if 'blinkStrength' in packet.keys():
377                                        # Skip any blink packets from log
378                                        continue
379                               
380                               
381                                timestamp = packet['timestamp']
382                                (date, localtime) = source.parseTimeStamp(timestamp, \
383                                                    truncate_time_zone=truncate_csv_timezone)
384                               
385                                csv[timestamp] = {}
386                                csv[timestamp]['Date'] = date
387                                csv[timestamp]['Time'] = localtime
388                               
389                                csv[timestamp]['Time From Start'] = ''
390                                csv[timestamp]['Headset On'] = ''
391                                csv[timestamp]['Contact Number Of Quality Channels'] = ''
392                                csv[timestamp]['Wireless'] = ''
393                                csv[timestamp]['Expressiv Action'] = ''
394                                csv[timestamp]['Excitement'] = ''
395                                csv[timestamp]['Long Term Excitement'] = ''
396                                csv[timestamp]['Meditation'] = ''
397                                csv[timestamp]['Frustration'] = ''
398                                csv[timestamp]['Engagement/Boredom'] = ''
399                                csv[timestamp]['Cognitiv Action'] = ''
400                                csv[timestamp]['Cognitiv Action Power'] = ''
401                               
402                                if self.emulate_thinkgear:
403                                        csv[timestamp]['Attention'] = ''
404                                        csv[timestamp]['Meditation'] = ''
405                                        csv[timestamp]['Signal Level'] = ''
406                                        #csv[timestamp]['Delta'] = ''
407                                        #csv[timestamp]['Theta'] = ''
408                                        #csv[timestamp]['Low Alpha'] = ''
409                                        #csv[timestamp]['High Alpha'] = ''
410                                        #csv[timestamp]['Low Beta'] = ''
411                                        #csv[timestamp]['High Beta'] = ''
412                                        #csv[timestamp]['Low Gamma'] = ''
413                                        #csv[timestamp]['Mid Gamma'] = ''
414                               
415                                for header in customDataHeaders:
416                                        csv[timestamp][header] = ''
417                       
418                       
419                        if 'emotivStatus' in packet.keys():
420                                if 'timeFromStart' in packet['emotivStatus'].keys():
421                                        csv[timestamp]['Time From Start'] = packet['emotivStatus']['timeFromStart']
422                                if 'headsetOn' in packet['emotivStatus'].keys():
423                                        csv[timestamp]['Headset On'] = packet['emotivStatus']['headsetOn']
424                                if 'Contact Number Of Quality Channels' in packet['emotivStatus'].keys():
425                                        csv[timestamp]['Contact Number Of Quality Channels'] = packet['emotivStatus']['contactNumberOfQualityChannels']
426                                if 'Wireless' in packet['emotivStatus'].keys():
427                                        csv[timestamp]['Wireless'] = packet['emotivStatus']['wireless']
428                       
429                        if 'expressiv' in packet.keys():
430                                if 'currentAction' in packet['expressiv'].keys():
431                                        value = packet['expressiv']['currentAction']
432                                        if value == 32:
433                                                csv[timestamp]['Expressiv Action'] = ''
434                                        else:
435                                                csv[timestamp]['Expressiv Action'] = packet['expressiv']['currentAction']
436                       
437                        if 'affectiv' in packet.keys():
438                                if 'excitement' in packet['affectiv'].keys():
439                                        csv[timestamp]['Excitement'] = int(packet['affectiv']['excitement'] * 100)
440                                if 'longTermExcitement' in packet['affectiv'].keys():
441                                        csv[timestamp]['Long Term Excitement'] = int(packet['affectiv']['longTermExcitement'] * 100)
442                                if 'meditation' in packet['affectiv'].keys():
443                                        csv[timestamp]['Meditation'] = int(packet['affectiv']['meditation'] * 100)
444                                if 'frustration' in packet['affectiv'].keys():
445                                        csv[timestamp]['Frustration'] = int(packet['affectiv']['frustration'] * 100)
446                                if 'engagementBoredom' in packet['affectiv'].keys():
447                                        csv[timestamp]['Engagement/Boredom'] = int(packet['affectiv']['engagementBoredom'] * 100)
448                       
449                        if 'cognitiv' in packet.keys():
450                                if 'currentAction' in packet['cognitiv'].keys():
451                                        csv[timestamp]['Cognitiv Action'] = packet['cognitiv']['currentAction']
452                                if 'currentActionPower' in packet['cognitiv'].keys():
453                                        csv[timestamp]['Cognitiv Action Power'] = int(packet['cognitiv']['currentActionPower'] * 100)
454                       
455                       
456                        if self.emulate_thinkgear:
457                                if 'eSense' in packet.keys():
458                                        if 'attention' in packet['eSense'].keys():
459                                                csv[timestamp]['Attention'] = packet['eSense']['attention']
460                                        if 'meditation' in packet['eSense'].keys():
461                                                csv[timestamp]['Meditation'] = packet['eSense']['meditation']
462                               
463                                if 'poorSignalLevel' in packet.keys():
464                                        csv[timestamp]['Signal Level'] = packet['poorSignalLevel']
465                               
466                                #if 'eegPower' in packet.keys():
467                                        #if 'delta' in packet['eegPower'].keys():
468                                                #csv[timestamp]['Delta'] = packet['eegPower']['delta']
469                                        #if 'theta' in packet['eegPower'].keys():
470                                                #csv[timestamp]['Theta'] = packet['eegPower']['theta']
471                                        #if 'lowAlpha' in packet['eegPower'].keys():
472                                                #csv[timestamp]['Low Alpha'] = packet['eegPower']['lowAlpha']
473                                        #if 'highAlpha' in packet['eegPower'].keys():
474                                                #csv[timestamp]['High Alpha'] = packet['eegPower']['highAlpha']
475                                        #if 'lowBeta' in packet['eegPower'].keys():
476                                                #csv[timestamp]['Low Beta'] = packet['eegPower']['lowBeta']
477                                        #if 'highBeta' in packet['eegPower'].keys():
478                                                #csv[timestamp]['High Beta'] = packet['eegPower']['highBeta']
479                                        #if 'lowGamma' in packet['eegPower'].keys():
480                                                #csv[timestamp]['Low Gamma'] = packet['eegPower']['lowGamma']
481                                        #if 'highGamma' in packet['eegPower'].keys():
482                                                #csv[timestamp]['Mid Gamma'] = packet['eegPower']['highGamma']
483                       
484                        for header in customDataHeaders:
485                                if 'custom' in packet.keys() and \
486                                   header in packet['custom'].keys():
487                                        csv[timestamp][header] = packet['custom'][header]
488               
489               
490                #if scrub_data:
491                        #csv = self.scrubData(csv, truncate_csv_timezone, source=source)
492               
493               
494                output = headers
495               
496                csv_keys = csv.keys()
497                csv_keys.sort()
498               
499                for key in csv_keys:
500                       
501                        row = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % \
502                              (csv[key]['Date'], \
503                               csv[key]['Time'], \
504                               csv[key]['Time From Start'], \
505                               csv[key]['Headset On'], \
506                               csv[key]['Contact Number Of Quality Channels'], \
507                               csv[key]['Wireless'], \
508                               csv[key]['Expressiv Action'], \
509                               csv[key]['Excitement'], \
510                               csv[key]['Long Term Excitement'], \
511                               csv[key]['Meditation'], \
512                               csv[key]['Frustration'], \
513                               csv[key]['Engagement/Boredom'], \
514                               csv[key]['Cognitiv Action'], \
515                               csv[key]['Cognitiv Action Power'])
516                       
517                        if self.emulate_thinkgear:
518                                #row = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s' % \
519                                row = '%s,%s,%s,%s' % \
520                                   (row, \
521                                    csv[key]['Attention'], \
522                                    csv[key]['Meditation'], \
523                                    csv[key]['Signal Level'])
524                                    #csv[key]['Delta'], \
525                                    #csv[key]['Theta'], \
526                                    #csv[key]['Low Alpha'], \
527                                    #csv[key]['High Alpha'], \
528                                    #csv[key]['Low Beta'], \
529                                    #csv[key]['High Beta'], \
530                                    #csv[key]['Low Gamma'], \
531                                    #csv[key]['Mid Gamma'])
532                       
533                        for header in customDataHeaders:
534                                row = row + ',%s' % csv[key][header]
535                       
536                        row = row + '\n'
537                       
538                        output = output + row
539               
540               
541                return(output) 
542       
543       
544        ##################################################################
545       
546        def exitThread(self, callThreadQuit=True):
547               
548                #if (self.emulate_headset_data):
549                        #try:
550                                #self.emulationTimer.stop()
551                        #except Exception, e:
552                                #if self.DEBUG:
553                                        #print "ERROR: Exception when stopping emulation timer:",
554                                        #print e
555               
556               
557                self.stopEmotivProtocol()
558               
559               
560                self.socket.close()
561               
562                if callThreadQuit:
563                        QtCore.QThread.quit(self)
564               
565                if self.parent == None:
566                        sys.exit()
567       
568       
569        ##################################################################
570       
571        def stopEmotivProtocol(self):
572               
573                if emotiv_protocol != None:
574                        emotiv_protocol.KEEP_RUNNING = False
575                       
576                        count = 1
577                        while emotiv_protocol.CONNECTED:
578                                time.sleep(0.10)
579                                count = count + 1
580                                if count >= 10:
581                                        break
582
Note: See TracBrowser for help on using the repository browser.