Example #1
0
class Thread(threading.Thread):

    def __init__(self, tty=TTY, baud_rate=BAUD_RATE, logger=None, *args,
                 **kwargs):
        if logger is None:
            self.logger = logging.getLogger('blipper.thread')
        else:
            self.logger = logger
        super(Thread, self).__init__(*args, **kwargs)
        self.tty = tty
        self.baud_rate = baud_rate
        self.ser = Serial(self.tty, self.baud_rate)
        self.ser.nonblocking()
        self.daemon = True
        self._handlers = defaultdict(list)
        self._should_exit = False
        self.waiting_for_packet = False

    def on(self, packet_type, handler):
        """Register a handler for the given packet type.

        If there are multiple handlers for a packet type, at most one
        should return a response. If no handler returns a response, a
        default OK response will be sent back.
        """
        self._handlers[packet_type].append(handler)

    def off(self, packet_type, handler):
        packet_handlers = self._handlers.get(packet_type, [])
        new_handlers = [h for h in packet_handlers if h != handler]
        self._handlers[packet_type] = new_handlers

    def send(self, packet):
        self.ser.write(bytes(packet))
        self.logger.debug('sent %r', packet)

    def get_packet(self):
        self.waiting_for_packet = True
        data = self.ser.read(Header.length)
        header = unpack_header(data)
        body = self.ser.read(header.body_length)
        cs = self.ser.read(1)
        self.waiting_for_packet = False

        cs_cmp = get_checksum(body)
        if cs != cs_cmp:
            raise PacketError("invalid body checksum")
        packet = packet_types[header.cmd].from_body(body)
        self.logger.debug('got %r', packet)
        return packet

    def run(self):
        while True:
            try:
                packet = self.get_packet()
                response = None
                packet_handlers = self._handlers.get(type(packet), [])
                for handler in packet_handlers:
                    handler_response = handler(packet)
                    if handler_response:
                        if response:
                            raise MultipleResponses
                        else:
                            response = handler_response
                if response is None:
                    response = packet.default_response()
                if response is not None:
                    self.ser.write(bytes(response))
            except Exception as e:
                if self._should_exit:  # exception expected
                    break
                else:
                    raise e

    def join(self, timeout=None):
        self._should_exit = True
        self.ser.close()
        super(Thread, self).join(timeout)