Changeset 127


Ignore:
Timestamp:
07/28/10 05:07:11 (11 years ago)
Author:
sc
Message:

thinkgear_emulator/puzzlebox_thinkgear_serial_protocol.py:

  • temporary save point prior to rollback to determine cause of device stream lockups
  • processing of EEG Band values added
  • processing of Raw EEG packets added
  • test code to handle proper closing of device added
File:
1 edited

Legend:

Unmodified
Added
Removed
  • thinkgear_emulator/puzzlebox_thinkgear_serial_protocol.py

    r126 r127  
    7575##################################################################### 
    7676 
    77 DEBUG = 2 
     77DEBUG = 3 
    7878 
    7979DEFAULT_SERIAL_PORT_WINDOWS = 'COM2' 
     
    106106 
    107107DEBUG_BYTE_COUNT = 819200 
    108 DEBUG_PACKET_COUNT = 128 
     108DEBUG_PACKET_COUNT = 1024 
    109109 
    110110##################################################################### 
     
    130130                 
    131131                self.device = serial_device 
     132                 
     133                self.keep_running = True 
    132134         
    133135         
     
    228230                                buffer = '' 
    229231                                 
    230                                 self.device.close() 
    231                                 sys.exit() 
     232                                self.keep_running = False 
     233                                self.device.stop() 
     234                                QtCore.QThread.quit(self) 
     235                                #sys.exit() 
     236         
     237         
     238        ################################################################## 
     239         
     240        def hexStringEndianSwap(self, theString): 
     241                """Rearranges character-couples in a little endian hex string to 
     242                convert it into a big endian hex string and vice-versa. i.e. 'A3F2' 
     243                is converted to 'F2A3' 
     244                 
     245                @param theString: The string to swap character-couples in 
     246                @return: A hex string with swapped character-couples. -1 on error. 
     247                 
     248                Taken from http://bytes.com/topic/python/answers/652429-convert-little-endian-hex-string-number#post2588668""" 
     249                 
     250                # We can't swap character couples in a string that has an odd number 
     251                # of characters. 
     252                if len(theString)%2 != 0: 
     253                        return -1 
     254                 
     255                # Swap the couples 
     256                swapList = [] 
     257                for i in range(0, len(theString), 2): 
     258                        swapList.insert(0, theString[i:i+2]) 
     259                 
     260                # Combine everything into one string. Don't use a delimeter. 
     261                return ''.join(swapList) 
     262         
     263         
     264        ################################################################## 
     265         
     266        def process_raw_eeg_value(self, data_values): 
     267                 
     268                '''SPEC: This Data Value consists of two bytes, and represents a  
     269                single raw wave sample. Its value is a signed 16-bit integer that  
     270                ranges from -32768 to 32767. The first byte of the Value represents  
     271                the high-order bits of the twos-compliment value, while the second  
     272                byte represents the low-order bits. To reconstruct the full raw  
     273                wave value, simply shift the rst byte left by 8 bits, and  
     274                bitwise-or with the second byte: 
     275                 
     276                short raw = (Value[0]<<8) | Value[1]; 
     277                 
     278                where Value[0] is the high-order byte, and Value[1] is the  
     279                low-order byte. In systems or languages where bit operations are  
     280                inconvenient, the following arithmetic operations may be  
     281                substituted instead: 
     282                 
     283                raw = Value[0]*256 + Value[1]; 
     284                if( raw >= 32768 ) raw = raw - 65536; 
     285                 
     286                where raw is of any signed number type in the language that can  
     287                represent all the numbers from -32768 to 32767. 
     288                 
     289                Each ThinkGear model reports its raw wave information in only  
     290                certain areas of the full -32768 to 32767 range. For example,  
     291                MindSet reports raw waves that fall between approximately -2048 to  
     292                2047. By default, output of this Data Value is enabled, and is  
     293                outputed 512 times a second, or approximately once every 2ms.''' 
     294                 
     295                high_order = data_values[0:2] 
     296                low_order = data_values[2:4] 
     297                 
     298                #high_order = high_order.encode("hex") 
     299                high_order = int(high_order, 16) 
     300                 
     301                #low_order = low_order.encode("hex") 
     302                low_order = int(low_order, 16) 
     303 
     304                raw = high_order * 256 + low_order 
     305                 
     306                if (raw >= 32768): 
     307                        raw = raw - 65536 
     308                 
     309                 
     310                return (raw) 
     311         
     312         
     313        ################################################################## 
     314         
     315        def process_asic_eeg_power(self, data_values): 
     316                 
     317                '''SPEC: This Data Value represents the current magnitude of 8  
     318                commonly-recognized types of EEG (brain-waves). This Data Value  
     319                is output as a series of eight 3-byte unsigned integers in  
     320                little-endian format.  
     321                The eight EEG powers are output in the following order:  
     322                delta (0.5 - 2.75Hz),  
     323                theta (3.5 - 6.75Hz),  
     324                low-alpha (7.5 - 9.25Hz),  
     325                high-alpha (10 - 11.75Hz),  
     326                low-beta (13 - 16.75Hz),  
     327                high-beta (18 - 29.75Hz),  
     328                low-gamma (31 - 39.75Hz), and  
     329                mid-gamma (41 - 49.75Hz).  
     330                These values have no units and therefore are only meaningful compared  
     331                to each other and to themselves, to consider relative quantity and  
     332                temporal uctuations. By default, output of this Data Value is enabled,  
     333                and is typically output once a second.''' 
     334                 
     335                eegPower = {} 
     336                 
     337                eegPower['delta'] = data_values[0:6] 
     338                eegPower['theta'] = data_values[6:12] 
     339                eegPower['lowAlpha'] = data_values[12:18] 
     340                eegPower['highAlpha'] = data_values[18:24] 
     341                eegPower['lowBeta'] = data_values[24:30] 
     342                eegPower['highBeta'] = data_values[30:36] 
     343                eegPower['lowGamma'] = data_values[36:42] 
     344                eegPower['highGamma'] = data_values[42:48] 
     345                 
     346                for key in eegPower.keys(): 
     347                        eegPower[key] = self.hexStringEndianSwap(eegPower[key]) 
     348                        #eegPower[key] = eegPower[key].encode("hex") 
     349                        eegPower[key] = int(eegPower[key], 16) 
     350                 
     351                 
     352                return(eegPower) 
    232353         
    233354         
     
    295416                                        print "Raw EEG:", 
    296417                                        print raw_wave_value 
     418                                raw_eeg_value = self.process_raw_eeg_value(data_values) 
     419                                if self.DEBUG > 2: 
     420                                        print "Raw EEG Value:", 
     421                                        print raw_eeg_value 
    297422                         
    298423                        elif code == '83': 
     
    301426                                        print "ASIC_EEG_POWER:", 
    302427                                        print asic_eeg_power 
    303                                  
     428                                eegPower = self.process_asic_eeg_power(data_values) 
     429                                if self.DEBUG > 1: 
     430                                        for key in eegPower.keys(): 
     431                                                print "%s: %i" % (key, eegPower[key]) 
     432                         
    304433                        else: 
    305434                                if self.DEBUG: 
     
    358487                                print " length:", 
    359488                                print length 
    360                                 print type(code) 
     489                                #print type(code) 
    361490                         
    362491                        data_values = '' 
     
    390519        ################################################################## 
    391520         
    392         #def process_packet(self, packet): 
    393                  
    394                 #'''Each Packet begins with its Header, followed by its Data Payload,  
    395                 #and ends with the Payload's Check-sum Byte, as follows: 
    396                 #[SYNC] [SYNC] [PLENGTH]      [PAYLOAD...]         [CHKSUM] 
    397                 #_______________________      _____________     ____________ 
    398                 #^^^^^^^^(Header)^^^^^^^      ^^(Payload)^^     ^(Checksum)^''' 
    399                  
    400                 #valid_length = False 
    401                 #valid_checksum = False 
    402                  
    403                 #if self.DEBUG > 3: 
    404                         #print packet 
    405                  
    406                  
    407                 ## SPEC: [PLENGTH] byte indicates the length, in bytes, of the  
    408                 ## Packet's Data Payload [PAYLOAD...] section, and may be any value  
    409                 ## from 0 up to 169. Any higher value indicates an error  
    410                 ## (PLENGTH TOO LARGE). Be sure to note that [PLENGTH] is the length  
    411                 ## of the Packet's Data Payload, NOT of the entire Packet.  
    412                 ## The Packet's complete length will always be [PLENGTH] + 4. 
    413                  
    414                 #packet_length = packet[2] 
    415                 #packet_length = packet_length.encode("hex") 
    416                 #packet_length = int(packet_length, 16) 
    417                  
    418                  
    419                 #if ((packet_length <= 169) and \ 
    420                          #(packet_length + 4) == (len(packet))): 
    421                          
    422                         #if self.DEBUG > 2: 
    423                                 #print "packet length correct" 
    424                          
    425                         #valid_length = True 
    426                  
    427                 #else: 
    428                         #if self.DEBUG: 
    429                                 #print "ERROR: packet length bad" 
    430                                 #print "packet_length:", 
    431                                 #print packet_length 
    432                                 #print "len(packet)+4:", 
    433                                 #print (len(packet) + 4) 
    434                  
    435                 #if valid_length: 
    436                          
    437                         #data_payload = packet[3:-1] 
    438                          
    439                         ## SPEC: The [CHKSUM] Byte must be used to verify the integrity of the 
    440                         ## Packet's Data Payload. The Payload's Checksum is defined as: 
    441                         ##  1. summing all the bytes of the Packet's Data Payload 
    442                         ##  2. taking the lowest 8 bits of the sum 
    443                         ##  3. performing the bit inverse (one's compliment inverse) 
    444                         ##     on those lowest 8 bits 
    445                          
    446                         #packet_checksum = packet[-1] 
    447                         #packet_checksum = packet_checksum.encode("hex") 
    448                         #packet_checksum = int(packet_checksum, 16) 
    449                          
    450                         #payload_checksum = 0 
    451                         #for byte in data_payload: 
    452                                 #value = byte.encode("hex") 
    453                                 #value = int(value, 16) 
    454                                 #payload_checksum += value 
    455                          
    456                         ## Take the lowest 8 bits of the calculated payload_checksum 
    457                         ## and invert them. Serious C code mojo. 
    458                         #payload_checksum &= 0xff 
    459                         #payload_checksum = ~payload_checksum & 0xff 
    460                          
    461                          
    462                         #if packet_checksum != payload_checksum: 
    463                                 #if self.DEBUG > 1: 
    464                                         #print "ERROR: packet checksum does not match" 
    465                                         #print "       packet_checksum:", 
    466                                         #print packet_checksum 
    467                                         #print "       payload_checksum:", 
    468                                         #print payload_checksum 
    469                          
    470                         #else: 
    471                                 #valid_checksum = True 
    472                                 #if self.DEBUG > 2: 
    473                                         #print "packet checksum correct" 
    474                                          
    475                                 #self.process_data_payload(data_payload) 
    476                  
    477                  
    478                 #return(valid_length, valid_checksum) 
    479          
    480          
    481         ################################################################## 
    482          
    483         #def process_byte(self, byte): 
    484                  
    485                 #self.buffer += byte 
    486                 #self.byte_count += 1 
    487                  
    488                 #if (len(self.buffer) > 2): 
    489                         #if self.buffer[-2:] == '\xAA\xAA': 
    490                                 ## New packet header found 
    491                                  
    492                                 #(valid_length, valid_checksum) = self.process_packet(self.buffer[:-2]) 
    493                                  
    494                                 #if ((valid_length) or \ 
    495                                          #(len(self.buffer) > 173)): 
    496                                         ## If processing the packet returned valid checks then we 
    497                                         ## restart reading the buffer to examine new packages. 
    498                                         ## However if the current buffer size is larger than 173 bytes 
    499                                         ## (the maximum possible packet length according to the protocol 
    500                                         ## specification document, then we still want to reset the buffer 
    501                                         ## because an error has occured in the stream) 
    502                                         #self.buffer = '\xAA\xAA' 
    503                                         #self.packet_count += 1 
    504                  
    505                  
    506                 #elif self.buffer == "AT+BRSF=24\r": 
    507                         ## This string is received when connecting to the wrong  
    508                         ## Bluetooth serial device channel of the ThinkGear device 
    509                         #if self.DEBUG: 
    510                                 #print "--> Received:", 
    511                                 #print self.buffer 
    512                         #response = '\r\nOK\r\n' 
    513                         #if self.DEBUG: 
    514                                 #print "<-- Sending:", 
    515                                 #print response.replace('\r\n', '') 
    516                         #self.device.write(response) 
    517                         #self.buffer = '' 
    518                          
    519                         #if self.DEBUG: 
    520                                 #print "ERROR: Serial device connected to wrong channel" 
    521                                 #print "(Consider changing from channel 1 to channel 3", 
    522                                 #print " or another COM port for example)" 
    523                          
    524                         #self.device.close() 
    525                         #sys.exit() 
    526                  
    527                  
    528                 #if ((self.DEBUG > 3) and \ 
    529                          #((self.byte_count >= DEBUG_BYTE_COUNT) or \ 
    530                           #(self.packet_count >= DEBUG_PACKET_COUNT))): 
    531                         #if self.DEBUG: 
    532                                 #print "max debugging count reached, disconnecting" 
    533                         #self.device.close() 
    534                         #sys.exit() 
    535          
    536          
    537         ################################################################## 
    538          
    539         #def start(self): 
    540                  
    541                 #self.buffer = '' 
    542                 #self.packet_count = 0 
    543                 #self.byte_count = 0 
    544                  
    545                 #while True: 
    546                          
    547                         #byte = self.device.read() 
    548                          
    549                         #if (len(byte) != 0): 
    550                                 #if DEBUG > 3: 
    551                                         #print byte 
    552                                          
    553                                 #self.process_byte(byte) 
    554          
    555          
    556         ################################################################## 
    557          
    558521        def parse_stream(self): 
    559522                 
     
    561524                packet_count = 0 
    562525                 
    563                 while True: 
     526                while self.keep_running: 
    564527                         
    565528                        # Synchronize on [SYNC] bytes 
     
    646609                                 
    647610                                self.process_data_payload(data_payload) 
    648                          
    649                          
    650                         if self.DEBUG > 3: 
    651                                 packet_count += 1 
    652                                 if packet_count >= DEBUG_PACKET_COUNT: 
    653                                         print "max debugging count reached, disconnecting" 
    654                                         self.device.close() 
    655                                         sys.exit() 
     611                                 
     612                                 
     613                                #if self.DEBUG > 1: 
     614                                        #packet_count += 1 
     615                                        #if packet_count >= DEBUG_PACKET_COUNT: 
     616                                                #print "max debugging count reached, disconnecting" 
     617                                                #self.keep_running = False 
     618                                                #self.device.stop() 
     619                                                #QtCore.QThread.quit(self) 
     620                                                ##sys.exit() 
    656621         
    657622         
     
    688653                                       QtCore.SIGNAL("timeout()"), \ 
    689654                                       self.check_buffer) 
    690                 self.buffer_check_timer.start(DEVICE_BUFFER_CHECK_TIMER) 
     655                #self.buffer_check_timer.start(DEVICE_BUFFER_CHECK_TIMER) 
     656                 
     657                self.keep_running = True 
    691658         
    692659         
     
    750717                 
    751718                 
    752                 # Initialize the modem 
    753                 #self.log.pdebug("Initializing %s modem" % modem_code) 
    754                  
    755719                device = serial.Serial(port = serial_port, \ 
    756720                                            baudrate = baudrate, \ 
     
    809773        ################################################################## 
    810774         
     775        def stop(self): 
     776                 
     777                self.keep_running = False 
     778                #self.device.close() 
     779                #QtCore.QThread.quit(self) 
     780         
     781         
     782        ################################################################## 
     783         
    811784        def close(self): 
    812          
     785                 
    813786                self.device.close() 
    814787         
     
    824797                self.buffer = '' 
    825798                 
     799                #while self.keep_running: 
     800                 
    826801                while True: 
    827802                         
    828                         byte = self.device.read() 
     803                        try: 
     804                                byte = self.device.read() 
     805                        except: 
     806                                if self.DEBUG: 
     807                                        print "ERROR: failed to read from serial device" 
     808                                break 
    829809                         
    830810                        if (len(byte) != 0): 
    831                                 if DEBUG > 3: 
     811                                if self.DEBUG > 2: 
    832812                                        print "Device read:", 
    833813                                        print byte 
    834814                                         
    835815                                self.buffer += byte 
     816                 
     817                 
     818                print "here" 
     819                self.device.close() 
     820                QtCore.QThread.quit(self) 
    836821 
    837822 
     
    864849        serial_device.start() 
    865850         
    866         protocol = puzzlebox_thinkgear_serial_protocol(log, \ 
    867                                                             serial_device, \ 
    868                                                             serial_port, \ 
    869                                                             DEBUG=DEBUG) 
    870          
    871         protocol.start() 
     851        #protocol = puzzlebox_thinkgear_serial_protocol(log, \ 
     852                                                            #serial_device, \ 
     853                                                            #serial_port, \ 
     854                                                            #DEBUG=DEBUG) 
     855         
     856        #protocol.start() 
    872857         
    873858        sys.exit(app.exec_()) 
    874859         
    875          
     860        print "there" 
Note: See TracChangeset for help on using the changeset viewer.