Callback for newly arrived packets for the memory port

def _new_packet_cb(self, packet):
        """Callback for newly arrived packets for the memory port"""
        chan = packet.channel
        cmd = packet.data[0]
        payload = packet.data[1:]

        if chan == CHAN_INFO:
            if cmd == CMD_INFO_NBR:
                self.nbr_of_mems = payload[0]
                logger.info('{} memories found'.format(self.nbr_of_mems))

                # Start requesting information about the memories,
                # if there are any...
                if self.nbr_of_mems > 0:
                    if not self._getting_count:
                        self._getting_count = True
                        logger.debug('Requesting first id')
                        pk = CRTPPacket()
                        pk.set_header(CRTPPort.MEM, CHAN_INFO)
                        pk.data = (CMD_INFO_DETAILS, 0)
                        self.cf.send_packet(pk, expected_reply=(
                            CMD_INFO_DETAILS, 0))
                else:
                    self._refresh_callback()

            if cmd == CMD_INFO_DETAILS:

                # Did we get a good reply, otherwise try again:
                if len(payload) < 5:
                    # Workaround for 1-wire bug when memory is detected
                    # but updating the info crashes the communication with
                    # the 1-wire. Fail by saying we only found 1 memory
                    # (the I2C).
                    logger.error(
                        '-------->Got good count, but no info on mem!')
                    self.nbr_of_mems = 1
                    if self._refresh_callback:
                        self._refresh_callback()
                        self._refresh_callback = None
                    return

                # Create information about a new memory
                # Id - 1 byte
                mem_id = payload[0]
                # Type - 1 byte
                mem_type = payload[1]
                # Size 4 bytes (as addr)
                mem_size = struct.unpack('I', payload[2:6])[0]
                # Addr (only valid for 1-wire?)
                mem_addr_raw = struct.unpack('B' * 8, payload[6:14])
                mem_addr = ''
                for m in mem_addr_raw:
                    mem_addr += '{:02X}'.format(m)

                if (not self.get_mem(mem_id)):
                    if mem_type == MemoryElement.TYPE_1W:
                        mem = OWElement(id=mem_id, type=mem_type,
                                        size=mem_size,
                                        addr=mem_addr, mem_handler=self)
                        self.mem_read_cb.add_callback(mem.new_data)
                        self.mem_write_cb.add_callback(mem.write_done)
                        self._ow_mems_left_to_update.append(mem.id)
                    elif mem_type == MemoryElement.TYPE_I2C:
                        mem = I2CElement(id=mem_id, type=mem_type,
                                         size=mem_size,
                                         mem_handler=self)
                        self.mem_read_cb.add_callback(mem.new_data)
                        self.mem_write_cb.add_callback(mem.write_done)
                    elif mem_type == MemoryElement.TYPE_DRIVER_LED:
                        mem = LEDDriverMemory(id=mem_id, type=mem_type,
                                              size=mem_size, mem_handler=self)
                        logger.debug(mem)
                        self.mem_read_cb.add_callback(mem.new_data)
                        self.mem_write_cb.add_callback(mem.write_done)
                    elif mem_type == MemoryElement.TYPE_LOCO:
                        mem = LocoMemory(id=mem_id, type=mem_type,
                                         size=mem_size, mem_handler=self)
                        logger.debug(mem)
                        self.mem_read_cb.add_callback(mem.new_data)
                    elif mem_type == MemoryElement.TYPE_TRAJ:
                        mem = TrajectoryMemory(id=mem_id, type=mem_type,
                                               size=mem_size, mem_handler=self)
                        logger.debug(mem)
                        self.mem_write_cb.add_callback(mem.write_done)
                    elif mem_type == MemoryElement.TYPE_LOCO2:
                        mem = LocoMemory2(id=mem_id, type=mem_type,
                                          size=mem_size, mem_handler=self)
                        logger.debug(mem)
                        self.mem_read_cb.add_callback(mem.new_data)
                    else:
                        mem = MemoryElement(id=mem_id, type=mem_type,
                                            size=mem_size, mem_handler=self)
                        logger.debug(mem)
                    self.mems.append(mem)
                    self.mem_added_cb.call(mem)

                    self._fetch_id = mem_id + 1

                if self.nbr_of_mems - 1 >= self._fetch_id:
                    logger.debug(
                        'Requesting information about memory {}'.format(
                            self._fetch_id))
                    pk = CRTPPacket()
                    pk.set_header(CRTPPort.MEM, CHAN_INFO)
                    pk.data = (CMD_INFO_DETAILS, self._fetch_id)
                    self.cf.send_packet(pk, expected_reply=(
                        CMD_INFO_DETAILS, self._fetch_id))
                else:
                    logger.debug(
                        'Done getting all the memories, start reading the OWs')
                    ows = self.get_mems(MemoryElement.TYPE_1W)
                    # If there are any OW mems start reading them, otherwise
                    # we are done
                    for ow_mem in ows:
                        ow_mem.update(self._mem_update_done)
                    if len(ows) == 0:
                        if self._refresh_callback:
                            self._refresh_callback()
                            self._refresh_callback = None

        if chan == CHAN_WRITE:
            id = cmd
            (addr, status) = struct.unpack('<IB', payload[0:5])
            logger.debug(
                'WRITE: Mem={}, addr=0x{:X}, status=0x{}'.format(
                    id, addr, status))
            # Find the read request
            if id in self._write_requests:
                self._write_requests_lock.acquire()
                wreq = self._write_requests[id][0]
                if status == 0:
                    if wreq.write_done(addr):
                        # self._write_requests.pop(id, None)
                        # Remove the first item
                        self._write_requests[id].pop(0)
                        self.mem_write_cb.call(wreq.mem, wreq.addr)

                        # Get a new one to start (if there are any)
                        if len(self._write_requests[id]) > 0:
                            self._write_requests[id][0].start()
                else:
                    logger.debug(
                        'Status {}: write resending...'.format(status))
                    wreq.resend()
                self._write_requests_lock.release()

        if chan == CHAN_READ:
            id = cmd
            (addr, status) = struct.unpack('<IB', payload[0:5])
            data = struct.unpack('B' * len(payload[5:]), payload[5:])
            logger.debug('READ: Mem={}, addr=0x{:X}, status=0x{}, '
                         'data={}'.format(id, addr, status, data))
            # Find the read request
            if id in self._read_requests:
                logger.debug(
                    'READING: We are still interested in request for '
                    'mem {}'.format(id))
                rreq = self._read_requests[id]
                if status == 0:
                    if rreq.add_data(addr, payload[5:]):
                        self._read_requests.pop(id, None)
                        self.mem_read_cb.call(rreq.mem, rreq.addr, rreq.data)
                else:
                    logger.debug('Status {}: resending...'.format(status))
                    rreq.resend()