예제 #1
0
파일: tau.py 프로젝트: ash2703/flirpy
class TeaxGrabber(Tau):
    """
    Data acquisition class for the Teax ThermalCapture Grabber USB
    
    """
    def __init__(self, vid=0x0403, pid=0x6010):
        self.dev = usb.core.find(idVendor=vid, idProduct=pid)

        self._ftdi = None
        
        if self.dev is not None:
            self.connect()
            self._sync_uart()
            #self._sync()
            
    def connect(self):
        reattach = False
        if self.dev.is_kernel_driver_active(0):
            reattach = True
            self.dev.detach_kernel_driver(0)
        
        self._claim_dev()
        
        self._ftdi = Ftdi()
        self._ftdi.open_from_device(self.dev)
        
        self._ftdi.set_bitmode(0xFF, Ftdi.BitMode.RESET)
        self._ftdi.set_bitmode(0xFF, Ftdi.BitMode.SYNCFF)
                  
    def _claim_dev(self):
        self.dev.reset()
        self._release()
        
        self.dev.set_configuration(1)

        usb.util.claim_interface(self.dev, 0)
        usb.util.claim_interface(self.dev, 1)
        
    def _release(self):
        for cfg in self.dev:
            for intf in cfg:
                if self.dev.is_kernel_driver_active(intf.bInterfaceNumber):
                    try:
                        self.dev.detach_kernel_driver(intf.bInterfaceNumber)
                    except usb.core.USBError as e:
                        print("Could not detatch kernel driver from interface({0}): {1}".format(intf.bInterfaceNumber, str(e)))
    
    def _read(self, n_bytes=0, packets_per_transfer=8, num_transfers=256):
        FTDI_PACKET_SIZE = 512
        
        if n_bytes == 0:
            n_bytes = packets_per_transfer * FTDI_PACKET_SIZE
  
        return self._ftdi.read_data(n_bytes)
                
    def _sync(self):
        data = self._read()
        
        magic = b"TEAX"
        
        while data.find(magic) == -1:
            data = self._read()
            
        return data[data.find(magic):]
    
    def _sync_uart(self, allow_timeout=False):
        data = self._read()
        
        magic = b"UART"
        
        t = time.time()
        while data.find(magic) == -1:
            data = self._read()
            
            if allow_timeout and time.time()-t > 0.2:
                break
            
        return data[data.find(magic):]

    def _convert_frame(self, data):
        raw_image = np.frombuffer(data[10:], dtype='uint8').reshape((512,2*642))
        raw_image = 0x3FFF & raw_image.view('uint16')[:,1:-1]
    
        return 0.04*raw_image - 273
    
    def _send_data(self, data):
        # header
        buffer = b"UART"
        buffer += int(len(data)).to_bytes(1, byteorder='big') # doesn't matter
        buffer += data
        #self._sync_uart(allow_timeout=True)
        self._ftdi.write_data(buffer)
        
    def _receive_data(self, length):
        
        length += length*5
        
        data = self._sync_uart()
        
        if len(data) < length:
            data += self._read(n_bytes=length-len(data))
            
            
        return data[:length][5::6]
        
    def grab(self, radiometric=True):
        
        data = b''
        data = self._sync()
        
        while len(data) < 657418:
            data += self._read(657418-len(data))
        
        if radiometric:
            data = self._convert_frame(data)
            
        return data
    
    def close(self):
        if self._ftdi is not None:
            self._ftdi.close()

    def __exit__(self, type, value, traceback):
        self.close()
        log.info("Disconnecting from camera.")
예제 #2
0
class TeaxGrabber(Tau):
    """
    Data acquisition class for the Teax ThermalCapture Grabber USB
    
    """
    def __init__(self, vid=0x0403, pid=0x6010, width=512, height=640):
        self.dev = usb.core.find(idVendor=vid, idProduct=pid)

        self._ftdi = None
        self.frame_size = 2*height*width+2058 # probably wrong for 320x256
        
        if self.dev is not None:
            self.connect()
            # Check for UART and TEAX magic strings, but 
            # it's OK if we timeout here
            self._sync_uart()
            # For some reason if we frame sync here, everything dies
            #self._sync(allow_timeout=True)
            
    def connect(self):
        if self.dev.is_kernel_driver_active(0):
            self.dev.detach_kernel_driver(0)
        
        self._claim_dev()
        
        self._ftdi = Ftdi()
        self._ftdi.open_from_device(self.dev)
        
        self._ftdi.set_bitmode(0xFF, Ftdi.BitMode.RESET)
        self._ftdi.set_bitmode(0xFF, Ftdi.BitMode.SYNCFF)
                  
    def _claim_dev(self):
        self.dev.reset()
        self._release()
        
        self.dev.set_configuration(1)

        usb.util.claim_interface(self.dev, 0)
        usb.util.claim_interface(self.dev, 1)
        
    def _release(self):
        for cfg in self.dev:
            for intf in cfg:
                if self.dev.is_kernel_driver_active(intf.bInterfaceNumber):
                    try:
                        self.dev.detach_kernel_driver(intf.bInterfaceNumber)
                    except usb.core.USBError as e:
                        print("Could not detatch kernel driver from interface({0}): {1}".format(intf.bInterfaceNumber, str(e)))
    
    def _read(self, n_bytes=0, packets_per_transfer=8, num_transfers=256):
        FTDI_PACKET_SIZE = 512
        
        if n_bytes == 0:
            n_bytes = packets_per_transfer * FTDI_PACKET_SIZE
  
        return self._ftdi.read_data(n_bytes)
                
    def _sync(self, allow_timeout=False):
        data = self._read()
        
        magic = b"TEAX"
        
        t = time.time()
        while data.find(magic) == -1:
            data = self._read()
            
            if not allow_timeout and time.time()-t > 0.2:
                log.warn("Timeout in frame sync")
                break
            elif time.time() -t > 0.2:
                break
            
        return data[data.find(magic):]
    
    def _sync_uart(self, allow_timeout=False):
        data = self._read()
        
        magic = b"UART"
        
        t = time.time()
        while data.find(magic) == -1:
            data = self._read()
            
            if not allow_timeout and time.time()-t > 0.2:
                log.warn("Timeout in command sync")
                break
            elif time.time() -t > 0.2:
                break
        
        return data[data.find(magic):]

    def _convert_frame(self, data, to_temperature=True):
        raw_image = np.frombuffer(data[10:], dtype='uint8').reshape((512,2*642))
        raw_image = 0x3FFF & raw_image.view('uint16')[:,1:-1]

        if to_temperature:
            return 0.04*raw_image - 273
        else:
            return raw_image
    
    def _send_data(self, data):
        # header
        buffer = b"UART"
        buffer += int(len(data)).to_bytes(1, byteorder='big') # doesn't matter
        buffer += data
        self._ftdi.write_data(buffer)
        
    def _receive_data(self, length):
        
        length += length*5
        
        data = self._sync_uart()
        
        if len(data) < length:
            data += self._read(n_bytes=length-len(data))
            
            
        return data[:length][5::6]
        
    def grab(self, to_temperature=True, retries=5):

        # Note that in TeAx's official driver, they use a threaded loop
        # to read data as it streams from the camera and they simply
        # process images/commands as they come back. There isn't the same 
        # sort of query/response structure that you'd normally see with
        # a serial device as the camera basically vomits data as soon as
        # the port opens.
        # 
        # The current approach here aims to allow a more structured way of
        # interacting with the camera by synchronising with the stream whenever
        # some particular data is requested. However in the future it may be better
        # if this is moved to a threaded function that continually services the
        # serial stream and we have some kind of helper function which responds 
        # to commands and waits to see the answer from the camera.
         
        for i in range(retries):

            data = b''
            data = self._sync()

            t = time.time()
            while len(data) < self.frame_size:
                data += self._read(n_bytes=self.frame_size-len(data))

                if time.time()-t > 0.2:
                    data = None
                    log.warn("Timeout in image capture")
                    break
            
            if len(data) == self.frame_size:
                break
            else:
                log.warn("Data size incorrect")
                data = None

        log.debug("Retries: {}".format(i))

        if data is not None:
            data = self._convert_frame(data, to_temperature=to_temperature)
            
        return data
    
    def close(self):
        if self._ftdi is not None:
            self._ftdi.close()

    def __exit__(self, type, value, traceback):
        self.close()
        log.info("Disconnecting from camera.")