source: trunk/synapse/Puzzlebox/Synapse/Protocol.py @ 193

Last change on this file since 193 was 193, checked in by sc, 12 years ago

trunk/synapse/Puzzlebox/Synapse/Interface.py:

  • saveData completed
  • exportData completed
  • resetData completed
  • collectData added
  • updateProfileSessionStatus added
  • calculateSessionTime added

trunk/synapse/Puzzlebox/Synapse/Protocol.py:

  • whitespace cleanup

trunk/synapse/Puzzlebox/Synapse/Server.py:

  • whitespace cleanup
  • Property svn:executable set to *
File size: 27.8 KB
Line 
1# -*- coding: utf-8 -*-
2
3# Copyright Puzzlebox Productions, LLC (2010)
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 Classes:
9#       puzzlebox_synapse_protocol_thinkgear = ProtocolHandler
10#       puzzlebox_synapse_protocol_thinkgear_serial_device = SerialDevice
11
12__changelog__ = """\
13Last Update: 2010.09.21
14
15"""
16
17__doc__ = """\
18Puzzlebox.Synapse.Protocol
19
20usage:
21  from Puzzlebox.Synapse import Protocol
22
23Modules:
24  Protocol.ProtocolHandler()
25  Protocol.SerialDevice()
26
27SPEC:
28
29 CODE Definitions Table
30 Single-Byte CODEs
31 Extended             (Byte)
32 Code Level   [CODE] [LENGTH] Data Value Meaning
33 ----------   ------ -------- ------------------
34           0    0x02        - POOR_SIGNAL Quality (0-255)
35           0    0x04        - ATTENTION eSense (0 to 100)
36           0    0x05        - MEDITATION eSense (0 to 100)
37           0    0x16        - Blink Strength. (0-255) Sent only
38                              when Blink event occurs.
39 Multi-Byte CODEs
40 Extended             (Byte)
41 Code Level   [CODE] [LENGTH] Data Value Meaning
42 ----------   ------ -------- ------------------
43           0    0x80        2 RAW Wave Value: a single big-endian
44                                16-bit two's-compliment signed value
45                                (high-order byte followed by
46                                low-order byte) (-32768 to 32767)
47           0    0x83       24 ASIC_EEG_POWER: eight big-endian
48                                3-byte unsigned integer values
49                                representing delta, theta, low-alpha
50                                high-alpha, low-beta, high-beta,
51                                low-gamma, and mid-gamma EEG band
52                                power values
53         Any    0x55        - NEVER USED (reserved for [EXCODE])
54         Any    0xAA        - NEVER USED (reserved for [SYNC])
55
56
57Linux Bluetooth serial protocol profile example:
58    rfcomm connect rfcomm0 00:13:EF:00:1B:FE 3
59
60TODO:
61 - needs to handle:
62   serial.serialutil.SerialException:
63   could not open port /dev/rfcomm0:
64   [Errno 16] Device or resource busy: '/dev/rfcomm0'
65
66"""
67
68### IMPORTS ###
69import sys, time
70import signal
71import serial
72
73if (sys.platform != 'win32'):
74        import bluetooth
75
76try:
77        import PySide as PyQt4
78        from PySide import QtCore
79except:
80        print "Using PyQt4 module"
81        from PyQt4 import QtCore
82else:
83        print "Using PySide module"
84
85import Configuration as configuration
86
87### GLOBALS ###
88
89DEBUG = 2
90
91THINKGEAR_DEVICE_SERIAL_PORT = configuration.THINKGEAR_DEVICE_SERIAL_PORT
92#THINKGEAR_DEVICE_BLUETOOTH_ADDRESS = \
93        #configuration.THINKGEAR_DEVICE_BLUETOOTH_ADDRESS
94
95DEFAULT_SERIAL_BAUDRATE = 57600
96
97#THINKGEAR_DEVICE_BLUETOOTH_ADDRESS = '00:13:EF:00:1B:FE'
98THINKGEAR_DEVICE_BLUETOOTH_CHANNEL = 3
99
100PROTOCOL_SYNC = '\xAA'
101PROTOCOL_EXCODE = '\x55'
102
103EEG_POWER_BAND_ORDER = configuration.THINKGEAR_EEG_POWER_BAND_ORDER
104
105DEVICE_BUFFER_CHECK_TIMER = 60 * 1000 # Check buffer size once every minute
106DEVICE_BUFFER_MAX_SIZE = 180 # Reset buffer if it grow this large
107                             # as this would indicate the processing
108                             # algorithm is not keeping up with the device
109                             # According to protocol specification,
110                             # "...a complete, valid Packet is ... a maximum
111                             # of 173 bytes long (possible if the Data Payload
112                             # is the maximum 169 bytes long)."
113                             # Therefore we reset if our buffer has grown longer
114                             # than the maximum packet length as this means
115                             # the processing algorthim is at least one full
116                             # packet behind.
117
118DEBUG_BYTE_COUNT = 819200
119DEBUG_PACKET_COUNT = 1024
120
121### CLASSES ###
122
123class ProtocolHandler(QtCore.QThread):
124       
125        def __init__(self, log, \
126                               serial_device, \
127                               DEBUG=DEBUG, \
128                               parent=None):
129               
130                QtCore.QThread.__init__(self,parent)
131               
132                self.log = log
133                self.DEBUG = DEBUG
134                self.parent = parent
135               
136                self.device = None
137                self.buffer = ''
138               
139                self.device = serial_device
140               
141                self.data_packet = {}
142                self.data_packet['eegPower'] = {}
143                self.data_packet['eSense'] = {}
144               
145                self.packet_count = 0
146                self.bad_packets = 0
147                self.session_start_time = None
148               
149                self.keep_running = True
150       
151       
152        ##################################################################
153       
154        def communicateWithHandsfreeProfile(self):
155               
156                #"AT+CKPD=200" - Indicates a Bluetooth button press
157                #"AT+VGM=" - Indicates a microphone volume change
158                #"AT+VGS=" - Indicates a speakerphone volume change
159                #"AT+BRSF=" - The Headset is asking what features are supported
160                #"AT+CIND?" - The Headset is asking about the indicators that are signaled
161                #"AT+CIND=?" - The Headset is asking about the test indicators
162                #"AT+CMER=" - The Headset is asking which indicates are registered for updates
163                #"ATA" - When an incoming call has been answered, usually a Bluetooth button press
164                #"AT+CHUP" - When a call has been hung up, usually a Bluetooth button press
165                #"ATD>" - The Headset is requesting the local device to perform a memory dial
166                #"ATD" - The Headset is requesting to dial the number
167                #"AT+BLDN" - The Headset is requesting to perform last number dialed
168                #"AT+CCWA=" - The Headset has enabled call waiting
169                #"AT+CLIP=" - The Headset has enabled CLI (Calling Line Identification)
170                #"AT+VTS=" - The Headset is asking to send DTMF digits
171                #"AT+CHLD=" - The Headset is asking to put the call on Hold
172                #"AT+BVRA=" - The Headset is requesting voice recognition
173                #"ATH" - Call hang-up
174               
175                #self.device.write('\x29')
176                #self.device.write('AT+BRSF=24\r\n')
177               
178                buffer = ''
179               
180                while True:
181                        reply = self.device.read()
182                       
183                        if (len(reply) != 0):
184                                if DEBUG > 1:
185                                        print reply
186                                buffer += reply
187                       
188                        if buffer == "AT+BRSF=24\r":
189                                print "--> Received:",
190                                print buffer
191                                response = '\r\nOK\r\n'
192                                print "<-- Sending:",
193                                print response.replace('\r\n', '')
194                                self.device.write(response)
195                                buffer = ''
196                       
197                        elif buffer == 'AT+CIND=?\r':
198                                print "--> Received:",
199                                print buffer
200                                # first field indicates that we have cellular service [0-1]
201                                # second field indicates that we're in a call (0 for false) [0-1]
202                                # third field indicates the current call setup (0 for idle) [0-3]
203                                response = '\r\n+CIND: 1,0,0\r\n'
204                                print "<-- Sending:",
205                                print response.replace('\r\n', '')
206                                self.device.write(response)
207                                response = '\r\nOK\r\n'
208                                print "<-- Sending:",
209                                print response.replace('\r\n', '')
210                                self.device.write(response)
211                                buffer = ''
212                       
213                        elif buffer == 'AT+CMER=3, 0, 0, 1\r':
214                                print "--> Received:",
215                                print buffer
216                                response = '\r\nOK\r\n'
217                                print "<-- Sending:",
218                                print response.replace('\r\n', '')
219                                self.device.write(response)
220                                response = '\r\n+CIEV:2,1\r\n'
221                                print "<-- Sending:",
222                                print response.replace('\r\n', '')
223                                self.device.write(response)
224                                response = '\r\n+CIEV:3,0\r\n'
225                                print "<-- Sending:",
226                                print response.replace('\r\n', '')
227                                self.device.write(response)
228                                buffer = ''
229                       
230                        elif buffer == 'AT+VGS=15\r':
231                                print "--> Received:",
232                                print buffer
233                                response = '\r\nOK\r\n'
234                                print "<-- Sending:",
235                                print response.replace('\r\n', '')
236                                self.device.write(response)
237                                buffer = ''
238                       
239                        elif buffer == 'AT+VGM=08\r':
240                                print "--> Received:",
241                                print buffer
242                                response = '\r\nOK\r\n'
243                                print "<-- Sending:",
244                                print response.replace('\r\n', '')
245                                self.device.write(response)
246                                buffer = ''
247                               
248                               
249                                self.exitThread()
250                                #self.keep_running = False
251                                #self.device.stop()
252                                #QtCore.QThread.quit(self)
253                                #sys.exit()
254       
255       
256        ##################################################################
257       
258        def hexStringEndianSwap(self, theString):
259                """Rearranges character-couples in a little endian hex string to
260                convert it into a big endian hex string and vice-versa. i.e. 'A3F2'
261                is converted to 'F2A3'
262               
263                @param theString: The string to swap character-couples in
264                @return: A hex string with swapped character-couples. -1 on error.
265               
266                Taken from http://bytes.com/topic/python/answers/652429-convert-little-endian-hex-string-number#post2588668"""
267               
268                # We can't swap character couples in a string that has an odd number
269                # of characters.
270                if len(theString)%2 != 0:
271                        return -1
272               
273                # Swap the couples
274                swapList = []
275                for i in range(0, len(theString), 2):
276                        swapList.insert(0, theString[i:i+2])
277               
278                # Combine everything into one string. Don't use a delimeter.
279                return ''.join(swapList)
280       
281       
282        ##################################################################
283       
284        def processRawEEGValue(self, data_values):
285               
286                '''SPEC: This Data Value consists of two bytes, and represents a
287                single raw wave sample. Its value is a signed 16-bit integer that
288                ranges from -32768 to 32767. The first byte of the Value represents
289                the high-order bits of the twos-compliment value, while the second
290                byte represents the low-order bits. To reconstruct the full raw
291                wave value, simply shift the rst byte left by 8 bits, and
292                bitwise-or with the second byte:
293               
294                short raw = (Value[0]<<8) | Value[1];
295               
296                where Value[0] is the high-order byte, and Value[1] is the
297                low-order byte. In systems or languages where bit operations are
298                inconvenient, the following arithmetic operations may be
299                substituted instead:
300               
301                raw = Value[0]*256 + Value[1];
302                if( raw >= 32768 ) raw = raw - 65536;
303               
304                where raw is of any signed number type in the language that can
305                represent all the numbers from -32768 to 32767.
306               
307                Each ThinkGear model reports its raw wave information in only
308                certain areas of the full -32768 to 32767 range. For example,
309                MindSet reports raw waves that fall between approximately -2048 to
310                2047. By default, output of this Data Value is enabled, and is
311                outputed 512 times a second, or approximately once every 2ms.'''
312               
313                high_order = data_values[0:2]
314                low_order = data_values[2:4]
315               
316                #high_order = high_order.encode("hex")
317                high_order = int(high_order, 16)
318               
319                #low_order = low_order.encode("hex")
320                low_order = int(low_order, 16)
321
322                raw = high_order * 256 + low_order
323               
324                if (raw >= 32768):
325                        raw = raw - 65536
326               
327               
328                return (raw)
329       
330       
331        ##################################################################
332       
333        def processAsicEegPower(self, data_values):
334               
335                '''SPEC: This Data Value represents the current magnitude of 8
336                commonly-recognized types of EEG (brain-waves). This Data Value
337                is output as a series of eight 3-byte unsigned integers in
338                little-endian format.
339                The eight EEG powers are output in the following order:
340                delta (0.5 - 2.75Hz),
341                theta (3.5 - 6.75Hz),
342                low-alpha (7.5 - 9.25Hz),
343                high-alpha (10 - 11.75Hz),
344                low-beta (13 - 16.75Hz),
345                high-beta (18 - 29.75Hz),
346                low-gamma (31 - 39.75Hz), and
347                mid-gamma (41 - 49.75Hz).
348                These values have no units and therefore are only meaningful compared
349                to each other and to themselves, to consider relative quantity and
350                temporal uctuations. By default, output of this Data Value is enabled,
351                and is typically output once a second.'''
352               
353                eegPower = {}
354               
355                eegPower['delta'] = data_values[0:6]
356                eegPower['theta'] = data_values[6:12]
357                eegPower['lowAlpha'] = data_values[12:18]
358                eegPower['highAlpha'] = data_values[18:24]
359                eegPower['lowBeta'] = data_values[24:30]
360                eegPower['highBeta'] = data_values[30:36]
361                eegPower['lowGamma'] = data_values[36:42]
362                eegPower['highGamma'] = data_values[42:48]
363               
364                for key in eegPower.keys():
365                        eegPower[key] = self.hexStringEndianSwap(eegPower[key])
366                        #eegPower[key] = eegPower[key].encode("hex")
367                        eegPower[key] = int(eegPower[key], 16)
368               
369               
370                return(eegPower)
371       
372       
373        ##################################################################
374       
375        def processDataRow(self, extended_code_level, code, length, data_values):
376               
377                '''CODE Definitions Table
378                   Single-Byte CODEs
379                   Extended             (Byte)
380                   Code Level   [CODE] [LENGTH] Data Value Meaning
381                   ----------   ------ -------- ------------------
382                             0    0x02        - POOR_SIGNAL Quality (0-255)
383                             0    0x04        - ATTENTION eSense (0 to 100)
384                             0    0x05        - MEDITATION eSense (0 to 100)
385                             0    0x16        - Blink Strength. (0-255) Sent only
386                                                when Blink event occurs.
387                   Multi-Byte CODEs
388                   Extended             (Byte)
389                   Code Level   [CODE] [LENGTH] Data Value Meaning
390                   ----------   ------ -------- ------------------
391                             0    0x80        2 RAW Wave Value: a single big-endian
392                                                  16-bit two's-compliment signed value
393                                                  (high-order byte followed by
394                                                  low-order byte) (-32768 to 32767)
395                             0    0x83       24 ASIC_EEG_POWER: eight big-endian
396                                                  3-byte unsigned integer values
397                                                  representing delta, theta, low-alpha
398                                                  high-alpha, low-beta, high-beta,
399                                                  low-gamma, and mid-gamma EEG band
400                                                  power values
401                           Any    0x55        - NEVER USED (reserved for [EXCODE])
402                           Any    0xAA        - NEVER USED (reserved for [SYNC])'''
403               
404                packet_update = {}
405               
406                self.packet_count += 1
407               
408                if extended_code_level == 0:
409                       
410                        if code == '02':
411                                poor_signal_quality = int(data_values, 16)
412                                if self.DEBUG > 1:
413                                        print # Empty line at the beginning of most packets
414                                        print "poorSignalLevel:",
415                                        print poor_signal_quality
416                               
417                                packet_update['poorSignalLevel'] = poor_signal_quality
418                       
419                       
420                        elif code == '04':
421                                attention = int(data_values, 16)
422                                if self.DEBUG > 1:
423                                        print "attention:",
424                                        print attention
425                               
426                                packet_update['eSense'] = {}
427                                packet_update['eSense']['attention'] = attention
428                       
429                       
430                        elif code == '05':
431                                meditation = int(data_values, 16)
432                                if self.DEBUG > 1:
433                                        print "meditation:",
434                                        print meditation
435                               
436                                packet_update['eSense'] = {}
437                                packet_update['eSense']['meditation'] = meditation
438                       
439                       
440                        elif code == '16':
441                                blink_strength = int(data_values, 16)
442                                if self.DEBUG > 1:
443                                        print "blinkStrength:",
444                                        print blink_strength
445                               
446                                packet_update['blinkStrength'] = blink_strength
447                       
448                       
449                        elif code == '80':
450                                #self.packet_count -= 1 # We don't count raw EEG packets for Interface
451                                raw_wave_value = data_values
452                                if self.DEBUG > 3:
453                                        print "Raw EEG:",
454                                        print raw_wave_value
455                                raw_eeg_value = self.processRawEEGValue(data_values)
456                                if self.DEBUG > 2:
457                                        print "Raw EEG Value:",
458                                        print raw_eeg_value
459                               
460                                packet_update['rawEeg'] = raw_eeg_value
461                       
462                       
463                        elif code == '83':
464                                asic_eeg_power = data_values
465                                if self.DEBUG > 2:
466                                        print "ASIC_EEG_POWER:",
467                                        print asic_eeg_power
468                                eegPower = self.processAsicEegPower(data_values)
469                                if self.DEBUG > 1:
470                                        for key in EEG_POWER_BAND_ORDER:
471                                                print "%s: %i" % (key, eegPower[key])
472                               
473                                packet_update['eegPower'] = {}
474                                for key in eegPower.keys():
475                                        packet_update['eegPower'][key] = eegPower[key]
476                       
477                       
478                        else:
479                                self.bad_packets += 1
480                                if self.DEBUG:
481                                        print "ERROR: data payload row code not matched"
482               
483               
484                return(packet_update)
485       
486       
487        ##################################################################
488       
489        def processDataPayload(self, data_payload):
490               
491                '''A DataRow consists of bytes in the following format:
492                ([EXCODE]...) [CODE] ([VLENGTH])   [VALUE...]
493                ____________________ ____________ ___________
494                ^^^^(Value Type)^^^^ ^^(length)^^ ^^(value)^^'''
495               
496               
497                if self.DEBUG > 3:
498                        print "data payload:",
499                        for byte in data_payload:
500                                print byte.encode("hex"),
501                        print
502               
503                byte_index = 0
504               
505                # Parse the extended_code_level, code, and length
506                while (byte_index < len(data_payload)):
507                        extended_code_level = 0
508                       
509                        # 1. Parse and count the number of [EXCODE] (0x55)
510                        #    bytes that may be at the beginning of the
511                        #    current DataRow.
512                        while (data_payload[byte_index] == PROTOCOL_EXCODE):
513                                extended_code_level += 1
514                                byte_index += 1
515                       
516                        # 2. Parse the [CODE] byte for the current DataRow.
517                        code = data_payload[byte_index]
518                        byte_index += 1
519                        code = code.encode("hex")
520                       
521                        # 3. If [CODE] >= 0x80, parse the next byte as the
522                        #    [VLENGTH] byte for the current DataRow.
523                        if (code > '\x7f'.encode("hex")):
524                                length = data_payload[byte_index]
525                                byte_index += 1
526                                length = length.encode("hex")
527                                length = int(length, 16)
528                        else:
529                                length = 1
530                       
531                       
532                        if self.DEBUG > 3:
533                                print "EXCODE level:",
534                                print extended_code_level,
535                                print " CODE:",
536                                print code,
537                                print " length:",
538                                print length
539                                #print type(code)
540                       
541                        data_values = ''
542                        value_index = 0
543                       
544                        # 4. Parse and handle the [VALUE...] byte(s) of the current
545                        #    DataRow, based on the DataRow's [EXCODE] level, [CODE],
546                        #    and [VLENGTH] (refer to the Code De nitions Table).
547                        while value_index < length:
548                                # Uh-oh more C mojo
549                                value = data_payload[(byte_index + value_index)] # & 0xFF
550                                data_values += value.encode("hex")
551                                value_index += 1
552                       
553                        if self.DEBUG > 3:
554                                print "Data Values:",
555                                print data_values
556                                print
557                       
558                        packet_update = self.processDataRow(extended_code_level, \
559                                                            code, \
560                                                            length, \
561                                                            data_values)
562                       
563                        self.updateDataPacket(packet_update)
564                       
565                       
566                        byte_index += length
567                       
568                        # 5. If not all bytes have been parsed from the payload[] array,
569                        # return to step 1. to continue parsing the next DataRow.
570       
571       
572        ##################################################################
573       
574        def parseStream(self):
575               
576                '''Each Packet begins with its Header, followed by its Data Payload,
577                and ends with the Payload's Check-sum Byte, as follows:
578                [SYNC] [SYNC] [PLENGTH]      [PAYLOAD...]         [CHKSUM]
579                _______________________      _____________     ____________
580                ^^^^^^^^(Header)^^^^^^^      ^^(Payload)^^     ^(Checksum)^'''
581               
582                # Loop forever, parsing one Packet per loop...
583                packet_count = 0
584               
585                while self.keep_running:
586                       
587                        # Synchronize on [SYNC] bytes
588                        # Read from stream until two consecutive [SYNC] bytes are found
589                        byte = self.device.read()
590                        if (byte != PROTOCOL_SYNC):
591                                continue
592                       
593                        byte = self.device.read()
594                        if (byte != PROTOCOL_SYNC):
595                                continue
596                       
597                       
598                        # Parse [PLENGTH] byte
599                       
600                        # SPEC: [PLENGTH] byte indicates the length, in bytes, of the
601                        # Packet's Data Payload [PAYLOAD...] section, and may be any value
602                        # from 0 up to 169. Any higher value indicates an error
603                        # (PLENGTH TOO LARGE). Be sure to note that [PLENGTH] is the length
604                        # of the Packet's Data Payload, NOT of the entire Packet.
605                        # The Packet's complete length will always be [PLENGTH] + 4.
606                       
607                        byte = self.device.read()
608                        packet_length = byte.encode("hex")
609                        packet_length = int(packet_length, 16)
610                       
611                        if (packet_length > 170):
612                                self.bad_packets += 1
613                                if self.DEBUG:
614                                        print "ERROR: packet length bad"
615                                        continue
616                       
617                       
618                        # Collect [PAYLOAD...] bytes
619                        data_payload = self.device.read(packet_length)
620                       
621                       
622                        # Calculate [PAYLOAD...] checksum
623                       
624                        # SPEC: The [CHKSUM] Byte must be used to verify the integrity of the
625                        # Packet's Data Payload. The Payload's Checksum is defined as:
626                        #  1. summing all the bytes of the Packet's Data Payload
627                        #  2. taking the lowest 8 bits of the sum
628                        #  3. performing the bit inverse (one's compliment inverse)
629                        #     on those lowest 8 bits
630                       
631                        payload_checksum = 0
632                        for byte in data_payload:
633                                value = byte.encode("hex")
634                                value = int(value, 16)
635                                payload_checksum += value
636                       
637                       
638                        # Take the lowest 8 bits of the calculated payload_checksum
639                        # and invert them. Serious C code mojo follows.
640                        payload_checksum &= 0xff
641                        payload_checksum = ~payload_checksum & 0xff
642                       
643                       
644                        # Parse [CKSUM] byte
645                        packet_checksum = self.device.read()
646                        packet_checksum = packet_checksum.encode("hex")
647                        packet_checksum = int(packet_checksum, 16)
648                       
649                       
650                        # Verify [CKSUM] byte against calculated [PAYLOAD...] checksum
651                        if packet_checksum != payload_checksum:
652                                self.bad_packets += 1
653                                if self.DEBUG > 1:
654                                        print "ERROR: packet checksum does not match"
655                                        print "       packet_checksum:",
656                                        print packet_checksum
657                                        print "       payload_checksum:",
658                                        print payload_checksum
659                                       
660                                        #self.device.checkBuffer()
661                               
662                                continue
663                       
664                       
665                        else:
666                                # Since [CKSUM] is OK, parse the Data Payload
667                                if self.DEBUG > 3:
668                                        print "packet checksum correct"
669                               
670                               
671                                self.processDataPayload(data_payload)
672                               
673                               
674                                #if self.DEBUG > 1:
675                                        #packet_count += 1
676                                        #if packet_count >= DEBUG_PACKET_COUNT:
677                                                #print "max debugging count reached, disconnecting"
678                                                #self.keep_running = False
679                                                #self.device.stop()
680                                                #QtCore.QThread.quit(self)
681                                                ##sys.exit()
682       
683       
684        ##################################################################
685       
686        def updateDataPacket(self, packet_update):
687               
688                if 'eSense' in packet_update.keys():
689                        process_packet = {'eSense': {}}
690                        for key in packet_update['eSense'].keys():
691                                self.data_packet['eSense'][key] = packet_update['eSense'][key]
692                                process_packet['eSense'][key] = packet_update['eSense'][key]
693               
694                else:
695                        self.data_packet.update(packet_update)
696                        process_packet = packet_update
697               
698               
699                if self.DEBUG > 3:
700                        print self.data_packet
701               
702               
703                if (self.parent != None):
704                        self.parent.processPacketThinkGear(process_packet)
705       
706       
707        ##################################################################
708       
709        def run(self):
710               
711                self.packet_count = 0
712                self.bad_packets = 0
713                self.session_start_timestamp = time.time()
714               
715                self.parseStream()
716       
717       
718        ##################################################################
719       
720        def exitThread(self, callThreadQuit=True):
721               
722                try:
723                        self.device.stop()
724                except:
725                        pass
726               
727                #self.wait()
728                if callThreadQuit:
729                        QtCore.QThread.quit(self)
730
731
732#####################################################################
733#####################################################################
734
735class SerialDevice(QtCore.QThread):
736       
737        def __init__(self, log, \
738                               device_address=THINKGEAR_DEVICE_SERIAL_PORT, \
739                               DEBUG=DEBUG, \
740                               parent=None):
741               
742                QtCore.QThread.__init__(self,parent)
743               
744                self.log = log
745                self.DEBUG = DEBUG
746               
747                self.device_address = device_address
748                self.device = None
749                self.buffer = ''
750               
751                if (self.device_address.count(':') == 5):
752                        # Device address is a Bluetooth MAC address
753                        self.device = self.initializeBluetoothDevice()
754                else:
755                        # Device address is a serial port address
756                        self.device = self.initializeSerialDevice()
757               
758                self.buffer_check_timer = QtCore.QTimer()
759                QtCore.QObject.connect(self.buffer_check_timer, \
760                                       QtCore.SIGNAL("timeout()"), \
761                                       self.checkBuffer)
762                self.buffer_check_timer.start(DEVICE_BUFFER_CHECK_TIMER)
763               
764                self.keep_running = True
765       
766       
767        ##################################################################
768       
769        def initializeBluetoothDevice(self):
770               
771                socket = bluetooth.BluetoothSocket( bluetooth.RFCOMM )
772               
773                try:
774                        socket.connect((self.device_address, THINKGEAR_DEVICE_BLUETOOTH_CHANNEL))
775               
776                except Exception, e:
777                        if self.DEBUG:
778                                print "ERROR:",
779                                print e
780                                sys.exit()
781               
782               
783                return socket
784       
785       
786        ##################################################################
787       
788        def initializeSerialDevice(self):
789               
790                baudrate = DEFAULT_SERIAL_BAUDRATE
791                bytesize = 8
792                parity = 'NONE'
793                stopbits = 1
794                software_flow_control = 'f'
795                rts_cts_flow_control = 'f'
796                #timeout = 15
797                timeout = 5
798               
799                # convert bytesize
800                if (bytesize == 5):
801                        init_byte_size = serial.FIVEBITS
802                elif (bytesize == 6):
803                        init_byte_size = serial.SIXBITS
804                elif (bytesize == 7):
805                        init_byte_size = serial.SEVENBITS
806                elif (bytesize == 8):
807                        init_byte_size = serial.EIGHTBITS
808                else:
809                        #self.log.perror("Invalid value for %s modem byte size! Using default (8)" % modem_type)
810                        init_byte_size = serial.EIGHTBITS
811               
812                # convert parity
813                if (parity == 'NONE'):
814                        init_parity = serial.PARITY_NONE
815                elif (parity == 'EVEN'):
816                        init_parity = serial.PARITY_EVEN
817                elif (parity == 'ODD'):
818                        init_parity = serial.PARITY_ODD
819                else:
820                        #self.log.perror("Invalid value for %s modem parity! Using default (NONE)" % modem_type)
821                        init_parity = serial.PARITY_NONE
822               
823                # convert stopbits
824                if (stopbits == 1):
825                        init_stopbits = serial.STOPBITS_ONE
826                elif (stopbits == 2):
827                        init_stopbits = serial.STOPBITS_TWO
828                else:
829                        #self.log.perror("Invalid value for %s modem stopbits! Using default (8)" % modem_type)
830                        init_byte_size = serial.STOPBITS_ONE
831               
832                # convert software flow control
833                if (software_flow_control == 't'):
834                        init_software_flow_control = 1
835                else:
836                        init_software_flow_control = 0
837               
838                # convert rts cts flow control
839                if (rts_cts_flow_control == 't'):
840                        init_rts_cts_flow_control = 1
841                else:
842                        init_rts_cts_flow_control = 0
843               
844               
845                try:
846##                      device = serial.Serial(port = self.device_address, \
847##                                                  baudrate = baudrate, \
848##                                                  bytesize = init_byte_size, \
849##                                                  parity = init_parity, \
850##                                                  stopbits = init_stopbits, \
851##                                                  xonxoff = init_software_flow_control, \
852##                                                  rtscts = init_rts_cts_flow_control, \
853##                                                  timeout = timeout)
854                       
855                        device = serialWrapper(port = self.device_address, \
856                                                    baudrate = baudrate, \
857                                                    bytesize = init_byte_size, \
858                                                    parity = init_parity, \
859                                                    stopbits = init_stopbits, \
860                                                    xonxoff = init_software_flow_control, \
861                                                    rtscts = init_rts_cts_flow_control, \
862                                                    timeout = timeout)
863               
864                except Exception, e:
865                        if self.DEBUG:
866                                print "ERROR:",
867                                print e,
868                                print self.device_address
869                                sys.exit()
870               
871               
872                device.flushInput()
873                #device.flushOutput()
874               
875               
876                return(device)
877       
878       
879        ##################################################################
880       
881        def checkBuffer(self):
882               
883                if self.DEBUG > 1:
884                        print "INFO: Buffer size check:",
885                        print len(self.buffer),
886                        print "(maximum before reset is %i)" % DEVICE_BUFFER_MAX_SIZE
887               
888                if (DEVICE_BUFFER_MAX_SIZE <= len(self.buffer)):
889                       
890                        if self.DEBUG:
891                                print "ERROR: Buffer size has grown too large, resetting"
892                       
893                        self.reset()
894       
895       
896        ##################################################################
897       
898        def reset(self):
899               
900                self.buffer = ''
901       
902       
903        ##################################################################
904       
905        def read(self, length=1):
906               
907                # Sleep for 2 ms if buffer is empty
908                # Based on 512 Hz refresh rate of NeuroSky MindSet device
909                # (1/512) * 1000 = 1.9531250
910                while len(self.buffer) < length:
911                        QtCore.QThread.msleep(2)
912                       
913                bytes = self.buffer[:length]
914               
915                self.buffer = self.buffer[length:]
916               
917                return(bytes)
918       
919       
920        ##################################################################
921       
922        def stop(self):
923               
924                self.keep_running = False
925                self.buffer_check_timer.stop()
926       
927       
928        ##################################################################
929       
930        def exitThread(self, callThreadQuit=True):
931               
932                self.stop()
933                self.close()
934               
935                if callThreadQuit:
936                        QtCore.QThread.quit(self)
937       
938       
939        ##################################################################
940       
941        def close(self):
942               
943                self.device.close()
944       
945       
946        ##################################################################
947       
948        def run(self):
949               
950                self.buffer = ''
951               
952                while self.keep_running:
953                       
954                        try:
955                                #byte = self.device.read()
956                                byte = self.device.recv(1)
957                               
958                                if (len(byte) != 0):
959                                        if self.DEBUG > 2:
960                                                print "Device read:",
961                                                print byte
962                                               
963                                        self.buffer += byte
964                       
965                        except:
966                                if self.DEBUG:
967                                        print "ERROR: failed to read from serial device"
968                                break
969               
970               
971                self.exitThread()
972
973
974#####################################################################
975#####################################################################
976
977class serialWrapper(serial.Serial):
978       
979        #__init__(port=None, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, writeTimeout=None, dsrdtr=False, interCharTimeout=None)
980       
981        def recv(self, size=1):
982               
983                return(self.read(size))
984
Note: See TracBrowser for help on using the repository browser.