コード例 #1
0
class FramedPacketConnection(object):
    """
    Creates a new packet connection.
    
    Parameters
    ----------
    callback : function
       The function that newly arrived packets should be passed to. Should have exactly one argument. 
    auto_reconnect: boolean
       Defines whether the socket should be automatically reopened after connection loss.
    framed: boolean
       Defines whether packets used in this connection are framed by start and end bytes. If false, each packet
       will contain exactly 1 byte.
    start_byte: byte
       If framed = True, use this as the start byte of a packet (default: '\xfc')
    end_byte: byte
       If framed = True, use this as the end byte of a packet (default: '\xfd')
    escape_byte: byte
       If framed = True, use this as the escape character. (default: '\xfe')
    octet_stuff_byte: byte
       If framed = True, use this byte to do octet stuffing and unstuffing on escaped characters. 
       
    """
    def __init__(self, callback, auto_reconnect = True, framed = True, start_byte = def_start_byte, end_byte = def_end_byte, 
                 escape_byte = def_escape_byte, octet_stuff_byte = def_octet_stuff_byte):
        self.callback = callback
        self.start_byte = start_byte
        self.end_byte = end_byte
        self.escape_byte = escape_byte
        self.octet_stuff_byte = octet_stuff_byte
        self.curr_packet = Packet()
        self.auto_reconnect = auto_reconnect
        self.framed = framed
        self.state = disconnected
        self.server = None   # Says whether this connection is running in server mode.

    
    """ Change the state of this Bluetooth Connection. Should only be used internally. """
    def change_state(self, new_state):
        if D: print "Changing state to " + repr(new_state)
        self.state = new_state
    
    """ Method to be called when a new byte comes in 
        on the open socket. Parses the bytes into packets. """ 
    def byte_callback(self, dat):
        #ipdb.set_trace()
        if dat == "":
            self.connection_reset()
            return
        
        if self.framed:
            if self.state == ready:
                if dat == self.start_byte:
                    self.curr_packet.set_start_time()
                    self.change_state(incoming)
                
            elif self.state == incoming:
                if dat == self.escape_byte:
                    self.change_state(escaping)
                elif dat == self.end_byte:
                    self.curr_packet.set_end_time()
                    self.change_state(received)
                else:
                    self.curr_packet.append_byte(dat)
                    
            elif self.state == escaping:
                dat = chr(ord(dat)^ord(self.octet_stuff_byte))
                self.curr_packet.append_byte(dat)
                self.change_state(incoming)
            
            if self.state == received:
                self.change_state(ready)
                self.callback(Packet(self.curr_packet))
                self.curr_packet = Packet()
                
        # In unframed mode, 1 byte = 1 packet.         
        else:
            self.change_state(incoming)
            self.curr_packet.append_byte(dat)
            self.change_state(ready)
            self.callback(Packet(self.curr_packet))
            self.curr_packet.set_start_time()
            self.curr_packet = Packet()
            
    
    """ Send raw data (without using packets). This method should only be used internally """
    def sendData(self, data):
        # XXX: This could wait for connection to be ready and then try again
        if self.state == ready:
            self.client_socket.send(data)
        else:
            if D: print "State is:  " + repr(self.state)
            ipdb.set_trace()
            if D: print "Connection is not ready, cannot send packet!"
    
    """ Frames and sends a packet over the connection """
    def sendPacket(self, pck):
        dat = pck.get_data()
        lst = []
        lst.append(self.start_byte)
        
        for i in range(len(dat)):
            if (self.needs_escaping(dat[i])):
                lst.append(self.escape_byte)
                # XXX: Ugly line of code.
                lst.append(chr(ord(dat[i])^ord(self.octet_stuff_byte)))
            else:
                lst.append(dat[i])
        
        lst.append(self.end_byte)
        print "Connection sending data: " + repr(lst)
        self.sendData("".join(lst))
    
    def connection_reset(self):
        if D: print "PacketConnection is being reset."
        self.curr_packet = Packet()
        
    def is_ready(self):
        return self.state == ready
    
    def is_disconnected(self):
        return (self.state == disconnected) or (self.state == dead)
    
    """ Returns whether a byte needs to be escaped in a packet. """
    def needs_escaping(self, dat):
        return (((dat == self.start_byte) or
                 (dat == self.end_byte)) or
                 (dat == self.escape_byte))