source: thinkgear_emulator/puzzlebox_thinkgear_serial_protocol.py @ 125

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

thinkgear_emulator/puzzlebox_thinkgear_serial_protocol.py:

  • QThread support added to prevent blocking of device stream
  • puzzlebox_thinkgear_serial_device class added
  • puzzlebox_thinkgear_serial_protocol class renamed
  • Property svn:executable set to *
File size: 25.8 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Network - Server - ThinkGear - Serial Protocol
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10#
11# Last Update: 2010.07.27
12#
13#####################################################################
14# SPEC:
15#
16# CODE Definitions Table
17# Single-Byte CODEs
18# Extended             (Byte)
19# Code Level   [CODE] [LENGTH] Data Value Meaning
20# ----------   ------ -------- ------------------
21#           0    0x02        - POOR_SIGNAL Quality (0-255)
22#           0    0x04        - ATTENTION eSense (0 to 100)
23#           0    0x05        - MEDITATION eSense (0 to 100)
24#           0    0x16        - Blink Strength. (0-255) Sent only
25#                              when Blink event occurs.
26# Multi-Byte CODEs
27# Extended             (Byte)
28# Code Level   [CODE] [LENGTH] Data Value Meaning
29# ----------   ------ -------- ------------------
30#           0    0x80        2 RAW Wave Value: a single big-endian
31#                                16-bit two's-compliment signed value
32#                                (high-order byte followed by
33#                                low-order byte) (-32768 to 32767)
34#           0    0x83       24 ASIC_EEG_POWER: eight big-endian
35#                                3-byte unsigned integer values
36#                                representing delta, theta, low-alpha
37#                                high-alpha, low-beta, high-beta,
38#                                low-gamma, and mid-gamma EEG band
39#                                power values
40#         Any    0x55        - NEVER USED (reserved for [EXCODE])
41#         Any    0xAA        - NEVER USED (reserved for [SYNC])
42#
43#####################################################################
44# Linux Bluetooth serial protocol profile example:
45#    rfcomm connect rfcomm0 00:13:EF:00:1B:FE 3
46#####################################################################
47# TODO:
48# - needs to handle:
49#   serial.serialutil.SerialException:
50#   could not open port /dev/rfcomm0:
51#   [Errno 16] Device or resource busy: '/dev/rfcomm0'
52#####################################################################
53
54import sys
55import signal
56import serial
57
58#try:
59        #import PySide as PyQt4
60        #from PySide import QtCore, QtGui, QtNetwork
61#except:
62        #print "Using PyQt4 module"
63        #from PyQt4 import QtCore, QtGui, QtNetwork
64#else:
65        #print "Using PySide module"
66       
67from PyQt4 import QtCore
68#from PySide import QtCore, QtGui, QtNetwork
69
70import puzzlebox_thinkgear_emulator_configuration as configuration
71#import puzzlebox_logger
72
73#####################################################################
74# Globals
75#####################################################################
76
77DEBUG = 2
78
79DEFAULT_SERIAL_PORT_WINDOWS = 'COM2'
80DEFAULT_SERIAL_PORT_LINUX = '/dev/rfcomm0'
81
82if (sys.platform == 'win32'):
83        DEFAULT_SERIAL_PORT = DEFAULT_SERIAL_PORT_WINDOWS
84else:
85        DEFAULT_SERIAL_PORT = DEFAULT_SERIAL_PORT_LINUX
86
87DEFAULT_SERIAL_BAUDRATE = 57600
88
89DEFAULT_MINDSET_ADDRESS = '00:13:EF:00:1B:FE'
90
91PROTOCOL_SYNC = '\xAA'
92PROTOCOL_EXCODE = '\x55'
93
94DEBUG_BYTE_COUNT = 819200
95DEBUG_PACKET_COUNT = 128
96
97#####################################################################
98# Classes
99#####################################################################
100
101class puzzlebox_thinkgear_serial_protocol(QtCore.QThread):
102       
103        def __init__(self, log, \
104                               serial_device, \
105                               serial_port=DEFAULT_SERIAL_PORT, \
106                               DEBUG=DEBUG, \
107                               parent=None):
108               
109                QtCore.QThread.__init__(self,parent)
110               
111                self.log = log
112                self.DEBUG = DEBUG
113               
114                self.serial_port = serial_port
115                self.device = None
116                self.buffer = ''
117               
118                #self.device = self.initialize_device()
119               
120                self.device = serial_device
121       
122       
123        ##################################################################
124       
125        #def initialize_device(self):
126               
127                #baudrate = DEFAULT_SERIAL_BAUDRATE
128                #bytesize = 8
129                #parity = 'NONE'
130                #stopbits = 1
131                #software_flow_control = 'f'
132                #rts_cts_flow_control = 'f'
133                ##timeout = 15
134                #timeout = 5
135               
136                ## convert bytesize
137                #if (bytesize == 5):
138                        #init_byte_size = serial.FIVEBITS
139                #elif (bytesize == 6):
140                        #init_byte_size = serial.SIXBITS
141                #elif (bytesize == 7):
142                        #init_byte_size = serial.SEVENBITS
143                #elif (bytesize == 8):
144                        #init_byte_size = serial.EIGHTBITS
145                #else:
146                        ##self.log.perror("Invalid value for %s modem byte size! Using default (8)" % modem_type)
147                        #init_byte_size = serial.EIGHTBITS
148               
149                ## convert parity
150                #if (parity == 'NONE'):
151                        #init_parity = serial.PARITY_NONE
152                #elif (parity == 'EVEN'):
153                        #init_parity = serial.PARITY_EVEN
154                #elif (parity == 'ODD'):
155                        #init_parity = serial.PARITY_ODD
156                #else:
157                        ##self.log.perror("Invalid value for %s modem parity! Using default (NONE)" % modem_type)
158                        #init_parity = serial.PARITY_NONE
159               
160                ## convert stopbits
161                #if (stopbits == 1):
162                        #init_stopbits = serial.STOPBITS_ONE
163                #elif (stopbits == 2):
164                        #init_stopbits = serial.STOPBITS_TWO
165                #else:
166                        ##self.log.perror("Invalid value for %s modem stopbits! Using default (8)" % modem_type)
167                        #init_byte_size = serial.STOPBITS_ONE
168               
169                ## convert software flow control
170                #if (software_flow_control == 't'):
171                        #init_software_flow_control = 1
172                #else:
173                        #init_software_flow_control = 0
174               
175                ## convert rts cts flow control
176                #if (rts_cts_flow_control == 't'):
177                        #init_rts_cts_flow_control = 1
178                #else:
179                        #init_rts_cts_flow_control = 0
180               
181               
182                ## Initialize the modem
183                ##self.log.pdebug("Initializing %s modem" % modem_code)
184               
185                #device = serial.Serial(port = serial_port, \
186                                            #baudrate = baudrate, \
187                                            #bytesize = init_byte_size, \
188                                            #parity = init_parity, \
189                                            #stopbits = init_stopbits, \
190                                            #xonxoff = init_software_flow_control, \
191                                            #rtscts = init_rts_cts_flow_control, \
192                                            #timeout = timeout)
193               
194               
195                #return(device)
196       
197       
198        ##################################################################
199       
200        def communicate_with_handsfree_profile(self):
201               
202                #"AT+CKPD=200" - Indicates a Bluetooth button press
203                #"AT+VGM=" - Indicates a microphone volume change
204                #"AT+VGS=" - Indicates a speakerphone volume change
205                #"AT+BRSF=" - The Headset is asking what features are supported
206                #"AT+CIND?" - The Headset is asking about the indicators that are signaled
207                #"AT+CIND=?" - The Headset is asking about the test indicators
208                #"AT+CMER=" - The Headset is asking which indicates are registered for updates
209                #"ATA" - When an incoming call has been answered, usually a Bluetooth button press
210                #"AT+CHUP" - When a call has been hung up, usually a Bluetooth button press
211                #"ATD>" - The Headset is requesting the local device to perform a memory dial
212                #"ATD" - The Headset is requesting to dial the number
213                #"AT+BLDN" - The Headset is requesting to perform last number dialed
214                #"AT+CCWA=" - The Headset has enabled call waiting
215                #"AT+CLIP=" - The Headset has enabled CLI (Calling Line Identification)
216                #"AT+VTS=" - The Headset is asking to send DTMF digits
217                #"AT+CHLD=" - The Headset is asking to put the call on Hold
218                #"AT+BVRA=" - The Headset is requesting voice recognition
219                #"ATH" - Call hang-up
220               
221                #self.device.write('\x29')
222                #self.device.write('AT+BRSF=24\r\n')
223               
224                buffer = ''
225               
226                while True:
227                        reply = self.device.read()
228                       
229                        if (len(reply) != 0):
230                                if DEBUG > 1:
231                                        print reply
232                                buffer += reply
233                       
234                        if buffer == "AT+BRSF=24\r":
235                                print "--> Received:",
236                                print buffer
237                                response = '\r\nOK\r\n'
238                                print "<-- Sending:",
239                                print response.replace('\r\n', '')
240                                self.device.write(response)
241                                buffer = ''
242                       
243                        elif buffer == 'AT+CIND=?\r':
244                                print "--> Received:",
245                                print buffer
246                                # first field indicates that we have cellular service [0-1]
247                                # second field indicates that we're in a call (0 for false) [0-1]
248                                # third field indicates the current call setup (0 for idle) [0-3]
249                                response = '\r\n+CIND: 1,0,0\r\n'
250                                print "<-- Sending:",
251                                print response.replace('\r\n', '')
252                                self.device.write(response)
253                                response = '\r\nOK\r\n'
254                                print "<-- Sending:",
255                                print response.replace('\r\n', '')
256                                self.device.write(response)
257                                buffer = ''
258                       
259                        elif buffer == 'AT+CMER=3, 0, 0, 1\r':
260                                print "--> Received:",
261                                print buffer
262                                response = '\r\nOK\r\n'
263                                print "<-- Sending:",
264                                print response.replace('\r\n', '')
265                                self.device.write(response)
266                                response = '\r\n+CIEV:2,1\r\n'
267                                print "<-- Sending:",
268                                print response.replace('\r\n', '')
269                                self.device.write(response)
270                                response = '\r\n+CIEV:3,0\r\n'
271                                print "<-- Sending:",
272                                print response.replace('\r\n', '')
273                                self.device.write(response)
274                                buffer = ''
275                       
276                        elif buffer == 'AT+VGS=15\r':
277                                print "--> Received:",
278                                print buffer
279                                response = '\r\nOK\r\n'
280                                print "<-- Sending:",
281                                print response.replace('\r\n', '')
282                                self.device.write(response)
283                                buffer = ''
284                       
285                        elif buffer == 'AT+VGM=08\r':
286                                print "--> Received:",
287                                print buffer
288                                response = '\r\nOK\r\n'
289                                print "<-- Sending:",
290                                print response.replace('\r\n', '')
291                                self.device.write(response)
292                                buffer = ''
293                               
294                                self.device.close()
295                                sys.exit()
296       
297       
298        ##################################################################
299       
300        def process_data_row(self, extended_code_level, code, length, data_values):
301               
302                '''CODE Definitions Table
303                   Single-Byte CODEs
304                   Extended             (Byte)
305                   Code Level   [CODE] [LENGTH] Data Value Meaning
306                   ----------   ------ -------- ------------------
307                             0    0x02        - POOR_SIGNAL Quality (0-255)
308                             0    0x04        - ATTENTION eSense (0 to 100)
309                             0    0x05        - MEDITATION eSense (0 to 100)
310                             0    0x16        - Blink Strength. (0-255) Sent only
311                                                when Blink event occurs.
312                   Multi-Byte CODEs
313                   Extended             (Byte)
314                   Code Level   [CODE] [LENGTH] Data Value Meaning
315                   ----------   ------ -------- ------------------
316                             0    0x80        2 RAW Wave Value: a single big-endian
317                                                  16-bit two's-compliment signed value
318                                                  (high-order byte followed by
319                                                  low-order byte) (-32768 to 32767)
320                             0    0x83       24 ASIC_EEG_POWER: eight big-endian
321                                                  3-byte unsigned integer values
322                                                  representing delta, theta, low-alpha
323                                                  high-alpha, low-beta, high-beta,
324                                                  low-gamma, and mid-gamma EEG band
325                                                  power values
326                           Any    0x55        - NEVER USED (reserved for [EXCODE])
327                           Any    0xAA        - NEVER USED (reserved for [SYNC])'''
328               
329               
330                if extended_code_level == 0:
331                       
332                        if code == '02':
333                                poor_signal_quality = int(data_values, 16)
334                                if self.DEBUG > 1:
335                                        print "POOR_SIGNAL Quality:",
336                                        print poor_signal_quality
337                       
338                        elif code == '04':
339                                attention = int(data_values, 16)
340                                if self.DEBUG > 1:
341                                        print "ATTENTION:",
342                                        print attention
343                       
344                        elif code == '05':
345                                meditation = int(data_values, 16)
346                                if self.DEBUG > 1:
347                                        print "MEDITATION:",
348                                        print meditation
349                       
350                        elif code == '16':
351                                blink_strength = int(data_values, 16)
352                                if self.DEBUG > 1:
353                                        print "Blink Strength:",
354                                        print blink_strength
355                       
356                        elif code == '80':
357                                raw_wave_value = data_values
358                                if self.DEBUG > 2:
359                                        print "Raw EEG:",
360                                        print raw_wave_value
361                       
362                        elif code == '83':
363                                asic_eeg_power = data_values
364                                if self.DEBUG > 1:
365                                        print "ASIC_EEG_POWER:",
366                                        print asic_eeg_power
367                               
368                        else:
369                                if self.DEBUG:
370                                        print "ERROR: data payload row code not matched"
371       
372       
373        ##################################################################
374       
375        def process_data_payload(self, data_payload):
376               
377                '''A DataRow consists of bytes in the following format:
378                ([EXCODE]...) [CODE] ([VLENGTH])   [VALUE...]
379                ____________________ ____________ ___________
380                ^^^^(Value Type)^^^^ ^^(length)^^ ^^(value)^^'''
381               
382                if self.DEBUG > 2:
383                        print "data payload:",
384                        for byte in data_payload:
385                                print byte.encode("hex"),
386                        print
387               
388                byte_index = 0
389               
390                # Parse the extended_code_level, code, and length
391                while (byte_index < len(data_payload)):
392                        extended_code_level = 0
393                       
394                        # 1. Parse and count the number of [EXCODE] (0x55)
395                        #    bytes that may be at the beginning of the
396                        #    current DataRow.
397                        while (data_payload[byte_index] == PROTOCOL_EXCODE):
398                                extended_code_level += 1
399                                byte_index += 1
400                       
401                        # 2. Parse the [CODE] byte for the current DataRow.
402                        code = data_payload[byte_index]
403                        byte_index += 1
404                        code = code.encode("hex")
405                       
406                        # 3. If [CODE] >= 0x80, parse the next byte as the
407                        #    [VLENGTH] byte for the current DataRow.
408                        if (code > '\x7f'.encode("hex")):
409                                length = data_payload[byte_index]
410                                byte_index += 1
411                                length = length.encode("hex")
412                                length = int(length, 16)
413                        else:
414                                length = 1
415                       
416                       
417                        if self.DEBUG > 2:
418                                print "EXCODE level:",
419                                print extended_code_level,
420                                print " CODE:",
421                                print code,
422                                print " length:",
423                                print length
424                                print type(code)
425                       
426                        data_values = ''
427                        value_index = 0
428                       
429                        # 4. Parse and handle the [VALUE...] byte(s) of the current
430                        #    DataRow, based on the DataRow's [EXCODE] level, [CODE],
431                        #    and [VLENGTH] (refer to the Code De nitions Table).
432                        while value_index < length:
433                                # Uh-oh more C mojo
434                                value = data_payload[(byte_index + value_index)] # & 0xFF
435                                data_values += value.encode("hex")
436                                value_index += 1
437                       
438                        if self.DEBUG > 2:
439                                print "Data Values:",
440                                print data_values
441                                print
442                       
443                        self.process_data_row(extended_code_level, \
444                                              code, \
445                                              length, \
446                                              data_values)
447                       
448                        byte_index += length
449                       
450                        # 5. If not all bytes have been parsed from the payload[] array,
451                        # return to step 1. to continue parsing the next DataRow.
452       
453       
454        ##################################################################
455       
456        def process_packet(self, packet):
457               
458                '''Each Packet begins with its Header, followed by its Data Payload,
459                and ends with the Payload's Check-sum Byte, as follows:
460                [SYNC] [SYNC] [PLENGTH]      [PAYLOAD...]         [CHKSUM]
461                _______________________      _____________     ____________
462                ^^^^^^^^(Header)^^^^^^^      ^^(Payload)^^     ^(Checksum)^'''
463               
464                valid_length = False
465                valid_checksum = False
466               
467                if self.DEBUG > 3:
468                        print packet
469               
470               
471                # SPEC: [PLENGTH] byte indicates the length, in bytes, of the
472                # Packet's Data Payload [PAYLOAD...] section, and may be any value
473                # from 0 up to 169. Any higher value indicates an error
474                # (PLENGTH TOO LARGE). Be sure to note that [PLENGTH] is the length
475                # of the Packet's Data Payload, NOT of the entire Packet.
476                # The Packet's complete length will always be [PLENGTH] + 4.
477               
478                packet_length = packet[2]
479                packet_length = packet_length.encode("hex")
480                packet_length = int(packet_length, 16)
481               
482                print "packet_length:",
483                print packet_length
484                print "  len(packet):",
485                print len(packet)
486               
487               
488                if ((packet_length <= 169) and \
489                         (packet_length + 4) == (len(packet))):
490                       
491                        if self.DEBUG > 2:
492                                print "packet length correct"
493                       
494                        valid_length = True
495               
496                else:
497                        if self.DEBUG:
498                                print "ERROR: packet length bad"
499               
500               
501                if valid_length:
502                       
503                        data_payload = packet[3:-1]
504                       
505                        # SPEC: The [CHKSUM] Byte must be used to verify the integrity of the
506                        # Packet's Data Payload. The Payload's Checksum is defined as:
507                        #  1. summing all the bytes of the Packet's Data Payload
508                        #  2. taking the lowest 8 bits of the sum
509                        #  3. performing the bit inverse (one's compliment inverse)
510                        #     on those lowest 8 bits
511                       
512                        packet_checksum = packet[-1]
513                        packet_checksum = packet_checksum.encode("hex")
514                        packet_checksum = int(packet_checksum, 16)
515                       
516                        payload_checksum = 0
517                        for byte in data_payload:
518                                value = byte.encode("hex")
519                                value = int(value, 16)
520                                payload_checksum += value
521                       
522                        # Take the lowest 8 bits of the calculated payload_checksum
523                        # and invert them. Serious C code mojo.
524                        payload_checksum &= 0xff
525                        payload_checksum = ~payload_checksum & 0xff
526                       
527                       
528                        if packet_checksum != payload_checksum:
529                                if self.DEBUG > 1:
530                                        print "ERROR: packet checksum does not match"
531                                        print "       packet_checksum:",
532                                        print packet_checksum
533                                        print "       payload_checksum:",
534                                        print payload_checksum
535                       
536                        else:
537                                valid_checksum = True
538                                if self.DEBUG > 2:
539                                        print "packet checksum correct"
540                                       
541                                self.process_data_payload(data_payload)
542               
543               
544                return(valid_length, valid_checksum)
545       
546       
547        ##################################################################
548       
549        def process_byte(self, byte):
550               
551                self.buffer += byte
552                self.byte_count += 1
553               
554                if (len(self.buffer) > 2):
555                        if self.buffer[-2:] == '\xAA\xAA':
556                                # New packet header found
557                               
558                                (valid_length, valid_checksum) = self.process_packet(self.buffer[:-2])
559                               
560                                if ((valid_length) or \
561                                         (len(self.buffer) > 173)):
562                                        # If processing the packet returned valid checks then we
563                                        # restart reading the buffer to examine new packages.
564                                        # However if the current buffer size is larger than 173 bytes
565                                        # (the maximum possible packet length according to the protocol
566                                        # specification document, then we still want to reset the buffer
567                                        # because an error has occured in the stream)
568                                        self.buffer = '\xAA\xAA'
569                                        self.packet_count += 1
570               
571               
572                elif self.buffer == "AT+BRSF=24\r":
573                        # This string is received when connecting to the wrong
574                        # Bluetooth serial device channel of the ThinkGear device
575                        if self.DEBUG:
576                                print "--> Received:",
577                                print self.buffer
578                        response = '\r\nOK\r\n'
579                        if self.DEBUG:
580                                print "<-- Sending:",
581                                print response.replace('\r\n', '')
582                        self.device.write(response)
583                        self.buffer = ''
584                       
585                        if self.DEBUG:
586                                print "ERROR: Serial device connected to wrong channel"
587                                print "(Consider changing from channel 1 to channel 3",
588                                print " or another COM port for example)"
589                       
590                        self.device.close()
591                        sys.exit()
592               
593               
594                if ((self.DEBUG > 3) and \
595                         ((self.byte_count >= DEBUG_BYTE_COUNT) or \
596                          (self.packet_count >= DEBUG_PACKET_COUNT))):
597                        if self.DEBUG:
598                                print "max debugging count reached, disconnecting"
599                        self.device.close()
600                        sys.exit()
601       
602       
603        ##################################################################
604       
605        #def start(self):
606               
607                #self.buffer = ''
608                #self.packet_count = 0
609                #self.byte_count = 0
610               
611                #while True:
612                       
613                        #byte = self.device.read()
614                       
615                        #if (len(byte) != 0):
616                                #if DEBUG > 3:
617                                        #print byte
618                                       
619                                #self.process_byte(byte)
620       
621       
622        ##################################################################
623       
624        def parse_stream(self):
625               
626                # Loop forever, parsing one Packet per loop...
627                packet_count = 0
628               
629                while True:
630                       
631                        # Synchronize on [SYNC] bytes
632                        # Read from stream until two consecutive [SYNC] bytes are found
633                        byte = self.device.read()
634                        if (byte != PROTOCOL_SYNC):
635                                continue
636                       
637                        byte = self.device.read()
638                        if (byte != PROTOCOL_SYNC):
639                                continue
640                       
641                       
642                        # Parse [PLENGTH] byte
643                       
644                        # SPEC: [PLENGTH] byte indicates the length, in bytes, of the
645                        # Packet's Data Payload [PAYLOAD...] section, and may be any value
646                        # from 0 up to 169. Any higher value indicates an error
647                        # (PLENGTH TOO LARGE). Be sure to note that [PLENGTH] is the length
648                        # of the Packet's Data Payload, NOT of the entire Packet.
649                        # The Packet's complete length will always be [PLENGTH] + 4.
650                       
651                        byte = self.device.read()
652                        packet_length = byte.encode("hex")
653                        packet_length = int(packet_length, 16)
654                       
655                        if (packet_length > 170):
656                                if self.DEBUG:
657                                        print "ERROR: packet length bad"
658                                        continue
659                       
660                       
661                        # Collect [PAYLOAD...] bytes
662                        data_payload = self.device.read(packet_length)
663                       
664                       
665                        # Calculate [PAYLOAD...] checksum
666                       
667                        # SPEC: The [CHKSUM] Byte must be used to verify the integrity of the
668                        # Packet's Data Payload. The Payload's Checksum is defined as:
669                        #  1. summing all the bytes of the Packet's Data Payload
670                        #  2. taking the lowest 8 bits of the sum
671                        #  3. performing the bit inverse (one's compliment inverse)
672                        #     on those lowest 8 bits
673                       
674                        payload_checksum = 0
675                        for byte in data_payload:
676                                value = byte.encode("hex")
677                                value = int(value, 16)
678                                payload_checksum += value
679                       
680                       
681                        # Take the lowest 8 bits of the calculated payload_checksum
682                        # and invert them. Serious C code mojo follows.
683                        payload_checksum &= 0xff
684                        payload_checksum = ~payload_checksum & 0xff
685                       
686                       
687                        # Parse [CKSUM] byte
688                        packet_checksum = self.device.read()
689                        packet_checksum = packet_checksum.encode("hex")
690                        packet_checksum = int(packet_checksum, 16)
691                       
692                       
693                        # Verify [CKSUM] byte against calculated [PAYLOAD...] checksum
694                        if packet_checksum != payload_checksum:
695                                if self.DEBUG > 1:
696                                        print "ERROR: packet checksum does not match"
697                                        print "       packet_checksum:",
698                                        print packet_checksum
699                                        print "       payload_checksum:",
700                                        print payload_checksum
701                               
702                                continue
703                       
704                       
705                        else:
706                                # Since [CKSUM] is OK, parse the Data Payload
707                                if self.DEBUG > 2:
708                                        print "packet checksum correct"
709                               
710                               
711                                self.process_data_payload(data_payload)
712                       
713                       
714                        if self.DEBUG > 3:
715                                packet_count += 1
716                                if packet_count >= DEBUG_PACKET_COUNT:
717                                        print "max debugging count reached, disconnecting"
718                                        self.device.close()
719                                        sys.exit()
720       
721       
722        ##################################################################
723       
724        def run(self):
725               
726                self.parse_stream()
727
728
729#####################################################################
730#####################################################################
731
732class puzzlebox_thinkgear_serial_device(QtCore.QThread):
733       
734        def __init__(self, log, \
735                               serial_port=DEFAULT_SERIAL_PORT, \
736                               DEBUG=DEBUG, \
737                               parent=None):
738               
739                QtCore.QThread.__init__(self,parent)
740               
741                self.log = log
742                self.DEBUG = DEBUG
743               
744                self.serial_port = serial_port
745                self.device = None
746                self.buffer = ''
747               
748                self.device = self.initialize_device()
749       
750       
751        ##################################################################
752       
753        def initialize_device(self):
754               
755                baudrate = DEFAULT_SERIAL_BAUDRATE
756                bytesize = 8
757                parity = 'NONE'
758                stopbits = 1
759                software_flow_control = 'f'
760                rts_cts_flow_control = 'f'
761                #timeout = 15
762                timeout = 5
763               
764                # convert bytesize
765                if (bytesize == 5):
766                        init_byte_size = serial.FIVEBITS
767                elif (bytesize == 6):
768                        init_byte_size = serial.SIXBITS
769                elif (bytesize == 7):
770                        init_byte_size = serial.SEVENBITS
771                elif (bytesize == 8):
772                        init_byte_size = serial.EIGHTBITS
773                else:
774                        #self.log.perror("Invalid value for %s modem byte size! Using default (8)" % modem_type)
775                        init_byte_size = serial.EIGHTBITS
776               
777                # convert parity
778                if (parity == 'NONE'):
779                        init_parity = serial.PARITY_NONE
780                elif (parity == 'EVEN'):
781                        init_parity = serial.PARITY_EVEN
782                elif (parity == 'ODD'):
783                        init_parity = serial.PARITY_ODD
784                else:
785                        #self.log.perror("Invalid value for %s modem parity! Using default (NONE)" % modem_type)
786                        init_parity = serial.PARITY_NONE
787               
788                # convert stopbits
789                if (stopbits == 1):
790                        init_stopbits = serial.STOPBITS_ONE
791                elif (stopbits == 2):
792                        init_stopbits = serial.STOPBITS_TWO
793                else:
794                        #self.log.perror("Invalid value for %s modem stopbits! Using default (8)" % modem_type)
795                        init_byte_size = serial.STOPBITS_ONE
796               
797                # convert software flow control
798                if (software_flow_control == 't'):
799                        init_software_flow_control = 1
800                else:
801                        init_software_flow_control = 0
802               
803                # convert rts cts flow control
804                if (rts_cts_flow_control == 't'):
805                        init_rts_cts_flow_control = 1
806                else:
807                        init_rts_cts_flow_control = 0
808               
809               
810                # Initialize the modem
811                #self.log.pdebug("Initializing %s modem" % modem_code)
812               
813                device = serial.Serial(port = serial_port, \
814                                            baudrate = baudrate, \
815                                            bytesize = init_byte_size, \
816                                            parity = init_parity, \
817                                            stopbits = init_stopbits, \
818                                            xonxoff = init_software_flow_control, \
819                                            rtscts = init_rts_cts_flow_control, \
820                                            timeout = timeout)
821               
822               
823                return(device)
824       
825       
826        ##################################################################
827       
828        def read(self, length=1):
829               
830                # Sleep for 2 ms if buffer is empty
831                # Based on 512 Hz refresh rate of NeuroSky MindSet device
832                # (1/512) * 1000 = 1.9531250
833                while len(self.buffer) < length:
834                        QtCore.QThread.msleep(2)
835                       
836                bytes = self.buffer[:length]
837               
838                self.buffer = self.buffer[length:]
839               
840                return(bytes)
841       
842       
843        ##################################################################
844       
845        def close(self):
846       
847                self.device.close()
848       
849       
850        ##################################################################
851       
852        def run(self):
853               
854                #if self.DEBUG:
855                        #print "<---- [%s]: Main thread running" % self.socket.name
856                        #self.exec_()
857               
858                self.buffer = ''
859               
860                while True:
861                       
862                        byte = self.device.read()
863                       
864                        if (len(byte) != 0):
865                                if DEBUG > 3:
866                                        print "Device read:",
867                                        print byte
868                                       
869                                self.buffer += byte
870
871
872#####################################################################
873# Main
874#####################################################################
875
876if __name__ == '__main__':
877       
878        # Perform correct KeyboardInterrupt handling
879        signal.signal(signal.SIGINT, signal.SIG_DFL)
880       
881        #log = puzzlebox_logger.puzzlebox_logger(logfile='server_thinkgear')
882        log = None
883       
884        # Collect default settings and command line parameters
885        serial_port = DEFAULT_SERIAL_PORT
886       
887        for each in sys.argv:
888               
889                if each.startswith("--port="):
890                        serial_port = each[ len("--port="): ]
891       
892       
893        app = QtCore.QCoreApplication(sys.argv)
894       
895        serial_device = puzzlebox_thinkgear_serial_device(log, \
896                                                               serial_port, \
897                                                               DEBUG=DEBUG)
898        serial_device.start()
899       
900        protocol = puzzlebox_thinkgear_serial_protocol(log, \
901                                                            serial_device, \
902                                                            serial_port, \
903                                                            DEBUG=DEBUG)
904       
905        #server.parse_stream()
906        protocol.start()
907       
908        sys.exit(app.exec_())
909       
910       
911       
Note: See TracBrowser for help on using the repository browser.