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

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

synapse/setup.py:

  • merged win32 version into same setup.py file

synapse/scripts/display_windows_requirements.sh:

  • initial checkin

synapse/setup.cfg:

  • added pyserial requirement for serialWrapper class

synapse/Puzzlebox/Synapse/Protocol.py:

  • import pyserial even under Linux for serialWrapper class

synapse/setup_win32.py:

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