def init(self, serial_number, settings=1):
        from numpy import zeros, nan
        print('')
        print('-------------INITIALIZING NEW CAMERA-----------')
        import PySpin
        from circular_buffer_numpy.queue import Queue
        from circular_buffer_numpy.circular_buffer import CircularBuffer
        self.acquiring = False

        self.cam = self.find_camera(serial_number=serial_number)
        self.nodes = self.get_nodes()

        self.height = self.get_height()
        self.width = self.get_width()
        self.queue = Queue((620, self.height + 1, self.width), dtype='uint16')
        self.analysis_buffer = CircularBuffer(shape=(100, 20), dtype='float64')
        self.last_image_time_buffer = CircularBuffer(shape=(6000, 20),
                                                     dtype='float64')
        self.last_image_time_buffer.buffer = self.last_image_time_buffer.buffer * nan
        self.timestamp_buffer = CircularBuffer(shape=(6000, 1),
                                               dtype='float64')
        self.last_image = zeros((self.height + 1, self.width), dtype='uint16')
        self.set_lut_enable(False)
        self.set_gamma_enable(False)
        #self.set_gamma(0.5)
        self.set_autoexposure('Off')
        self.set_autogain('Off')

        self.configure_transport()
        try:
            self.cam.AcquisitionStop()
            print("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            print("Acquisition was already stopped")

        print('setting pixel format Mono11Packed')
        self.cam.PixelFormat.SetValue(PixelFormat_Mono12p)

        self.set_exposure_mode('Timed')
        self.exposure_time = 63000  #53500
        self.gain = 0
        self.black_level = 15
        self.background = zeros((self.height + 1, self.width))
        self.background[:self.height, :] = 15
        self.background_flag = True

        self.conf_acq_and_trigger(settings=settings)
Beispiel #2
0
    def __init__(self):
        self.name = 'DI4108_DL'
        self.device_info = {}
        self.device_info['empty'] = 'empty'
        self.task_name_dict = {}
        self.task_name_dict['empty'] = 'empty'
        self.pr_rate = (self.pr_baserate) / self.pr_dec
        self.pr_buffer_size = (int(self.pr_packet_size * self.pr_rate), 10)
        self.queue = Queue(shape=self.pr_buffer_size, dtype='int16')
        self.OverflowFlag = False

        self.io_push_queue = None
        self.io_put_queue = None

        self.curr_dio = 127
        self.user_set_dio = self.curr_dio

        self.run_once_counter = 0

        self.threads = {}
Beispiel #3
0
    def init(self, serial_number, settings=1):
        from numpy import zeros, nan, ones
        info('')
        info('-------------INITIALIZING NEW CAMERA-----------')
        import PySpin
        from circular_buffer_numpy.queue import Queue

        self.cam = self.find_camera(serial_number=serial_number)

        for i in range(2):
            try:
                self.cam.BeginAcquisition()
                info("Acquisition Started")
            except PySpin.SpinnakerException as ex:
                info("Acquisition was already started")
            try:
                self.cam.AcquisitionStop()
                info("Acquisition ended")
            except PySpin.SpinnakerException as ex:
                info("Acquisition was already ended")

        self.nodes = self.get_nodes()

        #Transport Configuration
        self.configure_transport()

        #Configure Image Format
        self.configure_image()

        #Analog Configuration
        self.conf_acq_and_trigger(settings=settings)

        self.height = self.get_height()
        self.width = self.get_width()
        if (self.pixel_format == 'mono12p'):
            from lcp_video.analysis import get_mono12p_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width * 1.5)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12p_conversion_mask(self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif (self.pixel_format == 'mono12packed'):
            from lcp_video.analysis import get_mono12packed_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width * 1.5)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12packed_conversion_mask(
                self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif self.pixel_format == 'mono16' or self.pixel_format == 'mono12p_16':
            self.img_len = int(self.height * self.width)
            self.images_dtype = 'int16'
        self.queue = Queue(
            (self.queue_length, self.img_len + self.header_length),
            dtype=self.images_dtype)

        self.queue_frameID = Queue((self.queue_length, 2), dtype='float64')

        self.last_raw_image = zeros((self.img_len + self.header_length, ),
                                    dtype=self.images_dtype)

        from circular_buffer_numpy.circular_buffer import CircularBuffer
        self.hits_buffer = CircularBuffer((1350000, 2), dtype='float64')

        #Algorithms Configuration
        self.lut_enable = False
        self.gamma_enable = False
        self.autoexposure = 'Off'
        self.autogain = 'Off'

        try:
            self.cam.AcquisitionStop()
            info("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            info("Acquisition was already stopped")

        self.set_exposure_mode('Timed')
        self.exposure_time = 63000  #53500
        self.gain = 0
        self.black_level = 15

        self.image_threshold = zeros((self.height, self.width)) + 7

        self.image_median = zeros((self.height, self.width))
        self.image_median[:, :] = 15

        self.image_mean = zeros((self.height, self.width))
        self.image_mean[:, :] = 15
        self.image_mean_flag = True

        self.image_std = ones((self.height, self.width))
        self.image_std[:, :] = 0.8
        self.image_std_flag = True

        self.sigma_level = 6

        self.mask = zeros((self.height, self.width), dtype='bool')
        self.mask_flag = True

        self.last_frameID = -1
        self.num_of_missed_frames = 0
Beispiel #4
0
class FlirCamera():
    def __init__(self, name=None, system=None):
        """
        """
        from numpy import zeros, nan
        self.name = name
        self.system = system

        #Acquisition
        self.queue_length = 32
        self.acquiring = False
        self.header_length = 4096

        #Recording
        self.recording_filename = f'camera_{name}.hdf5'
        self.recording_root = '/mnt/ramdisk/'
        self.recording_N = 1
        self.recording = False
        self.recording_pointer = 0
        self.recording_chunk_pointer = 0
        self.recording_chunk_maxpointer = 65535

        self.write_to_hdf5_benchmark = []

        self.threads = {}

        #configuration Parameters
        self.nice = 0
        self.reverseX = 0
        self.reverseY = 0
        self.rotate = 0
        self.trigger = 'Software'

        self.calc_on_the_fly = False

    def init(self, serial_number, settings=1):
        from numpy import zeros, nan, ones
        info('')
        info('-------------INITIALIZING NEW CAMERA-----------')
        import PySpin
        from circular_buffer_numpy.queue import Queue

        self.cam = self.find_camera(serial_number=serial_number)

        for i in range(2):
            try:
                self.cam.BeginAcquisition()
                info("Acquisition Started")
            except PySpin.SpinnakerException as ex:
                info("Acquisition was already started")
            try:
                self.cam.AcquisitionStop()
                info("Acquisition ended")
            except PySpin.SpinnakerException as ex:
                info("Acquisition was already ended")

        self.nodes = self.get_nodes()

        #Transport Configuration
        self.configure_transport()

        #Configure Image Format
        self.configure_image()

        #Analog Configuration
        self.conf_acq_and_trigger(settings=settings)

        self.height = self.get_height()
        self.width = self.get_width()
        if (self.pixel_format == 'mono12p'):
            from lcp_video.analysis import get_mono12p_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width * 1.5)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12p_conversion_mask(self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif (self.pixel_format == 'mono12packed'):
            from lcp_video.analysis import get_mono12packed_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width * 1.5)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12packed_conversion_mask(
                self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif self.pixel_format == 'mono16' or self.pixel_format == 'mono12p_16':
            self.img_len = int(self.height * self.width)
            self.images_dtype = 'int16'
        self.queue = Queue(
            (self.queue_length, self.img_len + self.header_length),
            dtype=self.images_dtype)

        self.queue_frameID = Queue((self.queue_length, 2), dtype='float64')

        self.last_raw_image = zeros((self.img_len + self.header_length, ),
                                    dtype=self.images_dtype)

        from circular_buffer_numpy.circular_buffer import CircularBuffer
        self.hits_buffer = CircularBuffer((1350000, 2), dtype='float64')

        #Algorithms Configuration
        self.lut_enable = False
        self.gamma_enable = False
        self.autoexposure = 'Off'
        self.autogain = 'Off'

        try:
            self.cam.AcquisitionStop()
            info("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            info("Acquisition was already stopped")

        self.set_exposure_mode('Timed')
        self.exposure_time = 63000  #53500
        self.gain = 0
        self.black_level = 15

        self.image_threshold = zeros((self.height, self.width)) + 7

        self.image_median = zeros((self.height, self.width))
        self.image_median[:, :] = 15

        self.image_mean = zeros((self.height, self.width))
        self.image_mean[:, :] = 15
        self.image_mean_flag = True

        self.image_std = ones((self.height, self.width))
        self.image_std[:, :] = 0.8
        self.image_std_flag = True

        self.sigma_level = 6

        self.mask = zeros((self.height, self.width), dtype='bool')
        self.mask_flag = True

        self.last_frameID = -1
        self.num_of_missed_frames = 0

    def read_current_setting(self):
        """
        """
        string = ''
        exposure_time = camera.cam.ExposureTime.GetValue()
        print(f'exposure time, us = {round(exposure_time,0)}')

        # Timed TriggerWidth
        exposure_mode = self.cam.ExposureMode.GetCurrentEntry().GetSymbolic()
        print(f'exposure mode = {exposure_mode}')

        resulting_frame_rate = camera.cam.AcquisitionResultingFrameRate.GetValue(
        )

        trigger_source = camera.cam.TriggerSource.GetCurrentEntry(
        ).GetSymbolic()

        print(f'trigger selector = {trigger_source}')

        trigger_selector = camera.cam.TriggerSelector.GetCurrentEntry(
        ).GetSymbolic()
        print(f'trigger selector = {trigger_selector}')

        trigger_activation = camera.cam.TriggerActivation.GetCurrentEntry(
        ).GetSymbolic()

        print(f'trigger activation = {trigger_activation}')

        acquisition_frame_rate_enable = camera.cam.AcquisitionFrameRateEnable.GetValue(
        )
        print(
            f'acquisition frame rate enable = {acquisition_frame_rate_enable}')

        acquisition_frame_rate = camera.cam.AcquisitionFrameRate.GetValue()
        print(f'acquisition frame rate = {acquisition_frame_rate}')

        x_offset = self.cam.OffsetX.GetValue()
        y_offset = self.cam.OffsetY.GetValue()
        print(f'Offset (x,y) = ({x_offset},{y_offset})')

        width = self.cam.Width.GetValue()
        height = self.cam.Height.GetValue()
        print(f'frame (width,height) = ({width},{height})')

        pixel_format = self.cam.PixelFormat.GetCurrentEntry().GetSymbolic()
        print(f'pixel format = {pixel_format}')

    def close(sself):
        pass

    def kill(self):
        """
        """
        self.pause_acquisition()
        sleep(1)
        self.stop_acquisition()
        sleep(0.1)
        del self.cam
        self.system.ReleaseInstance()
        del self

    def reset_to_factory_settings(self):
        self.pause_acquisition()
        self.stop_acquisition()
        try:
            self.cam.AcquisitionStop()
            print("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            info("Acquisition was already stopped")
        self.cam.UserSetSelector.SetValue(PySpin.UserSetSelector_Default)
        self.cam.UserSetLoad()

    def configure_transport(self):
        cam = self.cam
        # Configure Transport Layer Properties
        cam.TLStream.StreamBufferHandlingMode.SetValue(
            PySpin.StreamBufferHandlingMode_OldestFirst)
        cam.TLStream.StreamBufferCountMode.SetValue(
            PySpin.StreamBufferCountMode_Manual)
        cam.TLStream.StreamBufferCountManual.SetValue(20)
        info(
            f"Buffer Handling Mode: {cam.TLStream.StreamBufferHandlingMode.GetCurrentEntry().GetSymbolic()}"
        )
        info(
            f"Buffer Count Mode: {cam.TLStream.StreamBufferCountMode.GetCurrentEntry().GetSymbolic()}"
        )
        info(
            f"Buffer Count: {cam.TLStream.StreamBufferCountManual.GetValue()}")
        info(
            f"Max Buffer Count: {cam.TLStream.StreamBufferCountManual.GetMax()}"
        )

    def deinit(self):
        self.stop_acquisition()
        self.cam.DeInit()

    def find_camera(self, serial_number=None):
        """
        looks for all cameras connected and returns cam object
        """
        cam = None
        cam_list = self.system.GetCameras()
        num_cameras = cam_list.GetSize()
        info(f'found {num_cameras} cameras')
        for i, cam in enumerate(cam_list):
            sn = cam.TLDevice.DeviceSerialNumber.GetValue()
            info(f'sn = {sn}')
            if serial_number == sn:
                self.serial_number = sn
                break
        cam_list.Clear()
        return cam

    def get_all_cameras(self):
        cam_list = self.system.GetCameras()
        num_cameras = cam_list.GetSize()
        info(f'found {num_cameras} cameras')
        cameras = []
        for i, cam in enumerate(cam_list):
            sn = cam.TLDevice.DeviceSerialNumber.GetValue()
            info(f'sn = {sn}')
            cameras.append(sn)
        cam_list.Clear()
        return cameras

    def get_nodes(self):
        import PySpin
        self.cam.Init()
        # Retrieve GenICam nodemap
        nodemap = self.cam.GetNodeMap()
        self.nodemap = nodemap
        nodes = {}
        nodes['auto_gain'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('GainAuto'))
        nodes['pixel_format'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('PixelFormat'))
        nodes['gain'] = PySpin.CEnumerationPtr(nodemap.GetNode('Gain'))
        nodes['acquisition_mode'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('AcquisitionMode'))
        nodes['exposure_time'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('ExposureTime'))
        return nodes

    def get_image_background(self, N=0):
        """
        function that acquires N images and calculates M1, M2 and threshold images.
        """
        from time import ctime, time, sleep
        import os
        from numpy import sqrt

        from lcp_video.procedures.procedures import stats_from_chunk, find_pathnames
        # Load or compute stats for first chunk in dataset.
        info(f'starting acquiring background image file')
        camera.recording_stop()
        old_recording_chunk_maxpointer = self.recording_chunk_maxpointer
        self.recording_chunk_maxpointer = 2
        sleep(1)
        string = ctime().replace(' ', '-').replace(':', '-')
        self.recording_init(N_frames=256,
                            name=f'background-{string}',
                            overwrite=True)
        self.queue.reset()
        self.recording_start()
        filename = self.recording_basefilename + '_0.raw.hdf5'
        while not os.path.exists(filename):
            sleep(1)
        camera.recording_stop()
        os.remove(self.recording_basefilename + '_1.tmpraw.hdf5')
        self.recording_chunk_maxpointer = old_recording_chunk_maxpointer
        # analysing raw file and creating .stats. and returning
        root = camera.recording_root
        terms = [self.recording_basefilename, '.raw.hdf5']
        median, mean, var, threshold = stats_from_chunk(
            find_pathnames(root, terms)[0])
        self.image_mean = mean
        self.image_std = sqrt(var)
        self.image_var = var
        self.image_median = median
        self.image_threshold = threshold

        info(f'starting acquiring background image file')

    def get_image_background_old(self, N=0):
        """
        function that acquires N images and calculates M1, M2 and threshold images.
        """
        from numpy import mean, var, copy, zeros, std, sqrt
        if N == 0:
            N = camera.queue.length
        raw = copy(self.queue.peek_last_N(N))
        img = zeros((N, self.height, self.width))
        for i in range(N):
            img[i] = self.convert_raw_to_image(raw[i])
        self.image_mean = mean(img, axis=0)
        self.image_std = sqrt(var(img, axis=0) + 0.5)

    def get_image(self):
        from lcp_video.analysis import mono12p_to_image
        self.last_raw_image *= 0
        if self.acquiring:
            image_result = self.cam.GetNextImage()
            timestamp = image_result.GetTimeStamp()
            frameid = image_result.GetFrameID()
            info(f'get : {timestamp},    {frameid}')
            if (self.last_frameID != -1) and (
                (frameid - self.last_frameID) != 1):
                missed = frameid - self.last_frameID
                self.num_of_missed_frames += missed
                info(
                    f'missed {missed} frames. {self.queue.global_rear}. Current frame ID {frameid}, last frame ID {self.last_frameID} '
                )
            self.last_frameID = frameid
            # Getting the image data as a numpy array
            image_res = image_result.GetData()
            if self.pixel_format == 'mono12p_16':
                image_data = mono12p_to_image(image_res, self.height,
                                              self.width)
            else:
                image_data = image_res
            image_result.Release()
        else:
            info('No Data in get image')
            image_data = zeros((self.height * self.width, ))

        pointer = self.img_len
        self.last_raw_image[:pointer] = image_data
        self.last_raw_image[pointer:pointer + 64] = self.get_image_header(
            value=int(time() * 1000000), length=64)
        self.last_raw_image[pointer + 64:pointer +
                            128] = self.get_image_header(value=timestamp,
                                                         length=64)
        self.last_raw_image[pointer + 128:pointer +
                            192] = self.get_image_header(value=frameid,
                                                         length=64)
        return self.last_raw_image

    def get_image_header(self, value=None, length=4096):
        from time import time
        from numpy import zeros
        from ubcs_auxiliary.numerical import bin_array
        arr = zeros((1, length))
        if value is None:
            t = int(time() * 1000000)
        else:
            t = value
        arr[0, :64] = bin_array(t, 64)
        return arr

    def bin_array(num, m):
        from numpy import uint8, binary_repr, array
        """Convert a positive integer num into an m-bit bit vector"""
        return array(list(binary_repr(num).zfill(m))).astype(uint8)

    def run_once(self):
        from time import time
        from numpy import zeros, array
        from lcp_video.analysis import mono12p_to_image
        if self.acquiring:
            raw = self.get_image().reshape(1, self.img_len + 4096)
            self.queue.enqueue(raw)
            if not self.recording and self.calc_on_the_fly:
                self.last_reshaped_image = mono12p_to_image(
                    raw[0, :self.img_len], self.height, self.width).reshape(
                        (self.height, self.width))
                hits = ((self.last_reshaped_image >
                         (self.image_threshold + self.image_median)) *
                        ~self.mask).sum()
                arr = zeros((1, 2))
                arr[0, 0] = time()
                arr[0, 1] = hits
                from EPICS_CA.CAServer import casput
                casput(f'{self.name.upper()}_CAMERA:HITS.RBV', hits)
                self.hits_buffer.append(arr)

    def run(self):
        while self.acquiring:
            self.run_once()

    def start_thread(self):
        from ubcs_auxiliary.multithreading import new_thread
        if not self.acquiring:
            self.start_acquisition()
            self.threads['acquisition'] = new_thread(self.run)

    def stop_thread(self):
        if self.acquiring:
            self.stop_acquisition()

    def resume_acquisition(self):
        """
        """
        from ubcs_auxiliary.multithreading import new_thread
        if not self.acquiring:
            self.acquiring = True
            self.threads['acquisition'] = new_thread(self.run)

    def pause_acquisition(self):
        """
        """
        self.acquiring = False

    def start_acquisition(self):
        """
        a wrapper to start acquisition of images.
        """
        self.acquiring = True
        self.cam.BeginAcquisition()

    def stop_acquisition(self):
        """
        a wrapper to stop acquisition of images.
        """
        self.acquiring = False
        try:
            self.cam.EndAcquisition()
            print("Acquisition ended")
        except PySpin.SpinnakerException as ex:
            info("Acquisition was already ended")

    def io_put(self):
        pass

    def io_get(self):
        pass

    def get_black_level(self):
        import traceback
        from numpy import nan
        all = nan
        analog = nan
        digital = nan

        try:
            self.cam.BlackLevelSelector.SetValue(0)
        except:
            error(
                f'The self.cam.BlackLevelSelector.SetValue(0) failed {traceback.format_exc()}'
            )
        try:
            all = self.cam.BlackLevel.GetValue() * 4095 / 100
        except:
            error(
                f'self.cam.BlackLevel.GetValue()*4095/100 failed {traceback.format_exc()}'
            )
        try:
            self.cam.BlackLevelSelector.SetValue(1)
            analog = self.cam.BlackLevel.GetValue() * 4095 / 100
        except:
            error(
                f'sself.cam.BlackLevelSelector.SetValue(1); analog = self.cam.BlackLevel.GetValue()*4095/100 failed {traceback.format_exc()}'
            )
        try:
            self.cam.BlackLevelSelector.SetValue(2)
            digital = self.cam.BlackLevel.GetValue() * 4095 / 100
        except:
            error(
                f'self.cam.BlackLevelSelector.SetValue(2); digital = self.cam.BlackLevel.GetValue()*4095/100 failed {traceback.format_exc()}'
            )
        try:
            self.cam.BlackLevelSelector.SetValue(0)
        except:
            error(
                f'self.cam.BlackLevelSelector.SetValue(0) failed {traceback.format_exc()}'
            )
        return {'all': all, 'analog': analog, 'digital': digital}

    def set_black_level(self, value):
        """
        """
        try:
            self.cam.BlackLevelSelector.SetValue(0)
            self.cam.BlackLevel.SetValue(value * 100 / 4095)
        except:
            error(
                f'self.cam.BlackLevelSelector.SetValue(0); self.cam.BlackLevel.SetValue(value*100/4095) failed {traceback.format_exc()}'
            )

    black_level = property(get_black_level, set_black_level)

    def get_temperature(self):
        """
        """
        temp = self.cam.DeviceTemperature.GetValue()
        return temp

    temperature = property(get_temperature)

    def get_fps():
        return nan

    def set_fps(value):
        pass

    fps = property(get_fps, set_fps)

    def get_gain(self):
        return self.cam.Gain.GetValue()

    def set_gain(self, value):
        if value >= self.cam.Gain.GetMax():
            value = self.cam.Gain.GetMax()
        elif value < self.cam.Gain.GetMin():
            value = self.cam.Gain.GetMin()
        self.cam.Gain.SetValue(value)

    gain = property(get_gain, set_gain)

    def get_autogain(self):
        if self.cam is not None:
            value = self.cam.GainAuto.GetValue()
            if value == 0:
                return 'Off'
            elif value == 1:
                return 'Once'
            elif value == 2:
                return 'Continuous'
        else:
            return None

    def set_autogain(self, value):
        node = self.nodes['auto_gain']
        off = node.GetEntryByName("Off")
        once = node.GetEntryByName("Once")
        continuous = node.GetEntryByName("Continuous")
        if value == 'Off':
            node.SetIntValue(off.GetValue())
        elif value == 'Once':
            node.SetIntValue(once.GetValue())
        elif value == 'Continuous':
            node.SetIntValue(continuous.GetValue())

    autogain = property(get_autogain, set_autogain)

    def get_serial_number(self):
        import PySpin
        device_serial_number = cam.TLDevice.DeviceSerialNumber.GetValue()
        return device_serial_number

    def get_acquisition_mode(self):
        node = self.nodes['acquisition_mode']

    def set_acquisition_mode(self, value):
        node = self.nodes['acquisition_mode']
        continious = node.GetEntryByName("Continuous")
        single_frame = node.GetEntryByName("SingleFrame")
        multi_frame = node.GetEntryByName("MultiFrame")
        if value == 'Continuous':
            mode = continious
        elif value == 'SingleFrame':
            mode = single_frame
        elif value == 'MultiFrame':
            mode = multi_frame
        info(f'setting acquisition mode {value}')
        self.stop_acquisition()
        node.SetIntValue(mode)
        self.start_acquisition()

    def get_lut_enable(self):
        """
        """
        if self.cam is not None:
            result = self.cam.lut_enable.GetValue()
        else:
            result = None
        return result

    def set_lut_enable(self, value):
        """
        """
        if self.cam is not None:
            info('setting Look Up Table Enable to False')
            self.cam.LUTEnable.SetValue(value)

    lut_enable = property(get_lut_enable, set_lut_enable)

    def get_gamma_enable(self):
        """
        """
        if self.cam is not None:
            result = self.cam.GammaEnable.GetValue()
        else:
            result = None
        return result

    def set_gamma_enable(self, value):
        """
        """
        if self.cam is not None:
            self.cam.GammaEnable.SetValue(value)
        info(f'setting gamma enable {value}')

    gamma_enable = property(get_gamma_enable, set_gamma_enable)

    def get_gamma(self):
        if self.cam is not None:
            result = None
            #result = self.cam.Gamma.GetValue()
        else:
            result = None
        return result

    def set_gamma(self, value):
        """
        """
        if self.cam is not None:
            result = None
            #self.cam.Gamma.SetValue(value)
        info(f'setting gamma {value}')

    gamma = property(get_gamma, set_gamma)

    def get_height(self):
        if self.cam is not None:
            reply = self.cam.Height.GetValue()
        else:
            reply = nan
        return reply

    def get_width(self):
        if self.cam is not None:
            reply = self.cam.Width.GetValue()
        else:
            reply = nan
        return reply

    def set_exposure_mode(self, mode=None):
        from PySpin import ExposureMode_Timed, ExposureMode_TriggerWidth
        info(f'Setting up ExposureMode to {mode}')
        if self.cam is not None:
            if mode == "Timed":
                self.cam.ExposureMode.SetValue(ExposureMode_Timed)
            elif mode == "TriggerWidth":
                self.cam.ExposureMode.SetValue(ExposureMode_TriggerWidth)

    def set_autoexposure(self, value='Off'):
        from PySpin import ExposureAuto_Off, ExposureAuto_Continuous, ExposureAuto_Once
        if value == 'Off':
            self.cam.ExposureAuto.SetValue(ExposureAuto_Off)
        elif value == 'Once':
            self.cam.ExposureAuto.SetValue(ExposureAuto_Once)
        elif value == 'Continuous':
            self.cam.ExposureAuto.SetValue(ExposureAuto_Continuous)
            info(f'setting gamma enable {value}')

    def get_autoexposure(self):
        value = self.cam.ExposureAuto.GetValue()
        if value == 0:
            return 'Off'
        elif value == 1:
            return 'Once'
        elif value == 2:
            return 'Continuous'
        else:
            return 'unknown'

    autoexposure = property(get_autoexposure, set_autoexposure)

    def set_exposure_time(self, value):
        if self.cam is not None:
            self.cam.ExposureTime.SetValue(value)
            self._exposure_time = value
        else:
            pass

    def get_exposure_time(self, ):
        if self.cam is not None:
            try:
                return self.cam.ExposureTime.GetValue()
            except:
                return -1
        else:
            return nan
        self._exposure_time = value

    exposure_time = property(get_exposure_time, set_exposure_time)

    def trigger_now(self):
        """
        software trigger for camera
        """
        self.cam.TriggerSoftware()

    def configure_image(self):
        import PySpin

        "Two different pixel formats: PixelFormat_Mono12p and PixelFormat_Mono12Packed"

        if self.reverseX == 1:
            print('reversing X axis')
            self.cam.ReverseX.SetValue(True, True)
        else:
            self.cam.ReverseX.SetValue(False, True)
        if self.reverseY == 1:
            print('reversing Y axis')
            self.cam.ReverseY.SetValue(True, True)
        else:
            self.cam.ReverseY.SetValue(False, True)

        info(f'setting pixel format {self.pixel_format}')
        if self.pixel_format == 'mono12p' or self.pixel_format == 'mono12p_16':
            try:
                self.cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono12p)
            except:
                print(
                    'cannot set PixelFormat.SetValue(PySpin.PixelFormat_Mono12p)'
                )

        elif self.pixel_format == 'mono12packed':
            try:
                self.cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono12Packed)
            except:
                print(
                    'cannot set PixelFormat.SetValue(PySpin.PixelFormat_Mono12Packed)'
                )
        elif self.pixel_format == 'mono16':
            try:
                self.cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono16)
            except:
                print(
                    'cannot set PixelFormat.SetValue(PySpin.PixelFormat_Mono16)'
                )

        width_max = self.cam.WidthMax.GetValue()
        height_max = self.cam.HeightMax.GetValue()

        old_offset_x = self.cam.OffsetX.GetValue()
        old_offset_y = self.cam.OffsetY.GetValue()
        new_offset_x = self.ROI_offset_x
        new_offset_y = self.ROI_offset_y

        old_width = self.cam.Width.GetValue()
        old_height = self.cam.Height.GetValue()
        new_height = self.ROI_height
        new_width = self.ROI_width
        try:
            if new_offset_x <= old_offset_x:
                info(f'setting ROI_offset_x: {self.ROI_offset_x}')
                self.cam.OffsetX.SetValue(self.ROI_offset_x)
                info(f'setting ROI_width: {self.ROI_width}')
                self.cam.Width.SetValue(self.ROI_width)
            else:
                info(f'setting ROI_width: {self.ROI_width}')
                self.cam.Width.SetValue(self.ROI_width)
                info(f'setting ROI_offset_x: {self.ROI_offset_x}')
                self.cam.OffsetX.SetValue(self.ROI_offset_x)
            if new_offset_y <= old_offset_y:
                info(f'setting ROI_offset_x: {self.ROI_offset_y}')
                self.cam.OffsetY.SetValue(self.ROI_offset_y)
                info(f'setting ROI_width: {self.ROI_width}')
                self.cam.Height.SetValue(self.ROI_height)
            else:
                info(f'setting ROI_width: {self.ROI_width}')
                self.cam.Width.SetValue(self.ROI_width)
                info(f'setting ROI_offset_x: {self.ROI_offset_x}')
                self.cam.OffsetX.SetValue(self.ROI_offset_x)

            info(f'setting ROI_offset_x: {self.ROI_offset_x}')
            self.cam.OffsetX.SetValue(self.ROI_offset_x)
            info(f'setting ROI_width: {self.ROI_width}')
            self.cam.Width.SetValue(self.ROI_width)

            info(f'setting ROI_height: {self.ROI_height}')
            self.cam.Height.SetValue(self.ROI_height)
            info(f'setting ROI_offset_y: {self.ROI_offset_y}')
            self.cam.OffsetY.SetValue(self.ROI_offset_y)
        except:
            pass

    def conf_acq_and_trigger(self, settings=1):
        """
        a collection of setting defined as appropriate for the selected modes of operation.

        settings 1 designed for external trigger mode of operation
        Acquisition Mode = Continuous
        Acquisition FrameRate Enable = False
        TriggerSource = Line 0
        TriggerMode = On
        TriggerSelector = FrameStart
        """

        if self.cam is not None:
            if settings == 1:
                info('Acquisition and Trigger Settings: 1')
                info('setting continuous acquisition mode')
                self.cam.AcquisitionMode.SetIntValue(
                    PySpin.AcquisitionMode_Continuous)
                info('setting frame rate enable to False')
                self.cam.AcquisitionFrameRateEnable.SetValue(False)

                if self.trigger == 'Line0':
                    info('setting TriggerSource Line0')
                    self.cam.TriggerSource.SetValue(PySpin.TriggerSource_Line0)
                    info('setting TriggerMode On')
                    self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_On)
                    info('setting TriggerSelector FrameStart')
                    self.cam.TriggerSelector.SetValue(
                        PySpin.TriggerSelector_FrameStart)
                    info('setting TriggerActivation RisingEdge')
                    self.cam.TriggerActivation.SetValue(
                        PySpin.TriggerActivation_RisingEdge)
                    info('setting TriggerOverlap ReadOnly ')
                    self.cam.TriggerOverlap.SetValue(
                        PySpin.TriggerOverlap_ReadOut)
                elif self.trigger == "Software":
                    info('setting TriggerSource Software')
                    self.cam.TriggerSource.SetValue(
                        PySpin.TriggerSource_Software)
                    info('setting TriggerMode On')
                    self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_Off)
                else:
                    info('setting TriggerSource Software')
                    self.cam.TriggerSource.SetValue(
                        PySpin.TriggerSource_Software)
                    info('setting TriggerMode On')
                    self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_Off)

            elif settings == 2:
                info('Acquisition and Trigger Settings: 2')
                info('setting SingleFrame acquisition mode')
                self.cam.AcquisitionMode.SetIntValue(
                    PySpin.AcquisitionMode_SingleFrame)
                info('setting frame rate enable to False')
                self.cam.AcquisitionFrameRateEnable.SetValue(False)

                info('setting frame rate enable to False')
                self.cam.AcquisitionFrameRateEnable.SetValue(False)
                info('setting TriggerMode On')
                self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_Off)

            elif settings == 3:
                info('Acquisition and Trigger Settings: 3 (software)')
                info('setting continuous acquisition mode')
                self.cam.AcquisitionMode.SetIntValue(
                    PySpin.AcquisitionMode_Continuous)

                info('setting frame rate enable to True')
                self.cam.AcquisitionFrameRateEnable.SetValue(True)
                info('setting frame rate to 1')
                self.cam.AcquisitionFrameRate.SetValue(20.0)
                info('setting TriggerMode Off')
                self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_Off)
                info('setting TriggerSource Line0')
                self.cam.TriggerSource.SetValue(PySpin.TriggerSource_Line0)
                info('setting TriggerSource Software')
                self.cam.TriggerSource.SetValue(PySpin.TriggerSource_Software)

    def convert_raw_to_image(self, rawdata):
        """
        """
        from lcp_video.analysis import mono12p_to_image, mono12packed_to_image
        from numpy import right_shift

        rawdata = rawdata[:self.img_len]
        print(f'rawdata = {rawdata.dtype}')
        if self.pixel_format == 'mono12p':
            image = mono12p_to_image(rawdata=rawdata,
                                     height=self.height,
                                     width=self.width)
        elif self.pixel_format == 'mono12packed':
            mask = self.conversion_mask
            mask8 = self.conversion_mask8
            image = mono12packe_to_image(rawdata=rawdata,
                                         height=self.height,
                                         width=self.width,
                                         mask=mask,
                                         mask8=mask8)
        elif self.pixel_format == 'mono16':
            image = right_shift(rawdata, 4).reshape((self.height, self.width))
        elif self.pixel_format == 'mono12p_16':
            image = rawdata.reshape((self.height, self.width))
        return image


# Recording

    def recording_init(self, N_frames=1200, name='', overwrite=False):
        """
        Initializes recording
        """
        self.recording_basefilename = self.recording_root + f'{self.name}_{name}'
        self.recording_chunk_pointer = 0
        filename = self.recording_basefilename + '_' + str(
            self.recording_chunk_pointer) + '.tmpraw.hdf5'
        self.recording_create_file(filename=filename,
                                   N_frames=N_frames,
                                   overwrite=overwrite)
        self.recording_Nframes = N_frames
        self.recording_pointer = 0

    def recording_create_file(self, filename, N_frames, overwrite=False):
        """
        creates hdf5 file on a drive prior to recording
        """
        from os.path import exists
        from h5py import File
        from time import time, sleep, ctime
        from numpy import zeros
        file_action = 'a'
        if exists(filename):
            if overwrite:
                info(
                    f'The HDF5 file exists but will be overwritten. The HDF5 was created. The file name is {filename}'
                )
                file_action = 'w'
            else:
                info(f' ----WARNING----')
                info(
                    f' The HDF5 file exists. Please delete it first! or use parameter overwrite = True to force deletion and creating of new file.'
                )
        else:
            info(f': The HDF5 was created. The file name is {filename}')
            with File(filename, file_action) as f:
                f.create_dataset('pixel format', data=self.pixel_format)
                f.create_dataset('exposure time', data=self.exposure_time)
                f.create_dataset('black level all',
                                 data=self.black_level['all'])
                f.create_dataset('black level analog',
                                 data=self.black_level['analog'])
                f.create_dataset('black level digital',
                                 data=self.black_level['digital'])
                f.create_dataset('image width', data=self.width)
                f.create_dataset('image height', data=self.height)
                f.create_dataset('image offset x', data=self.ROI_offset_x)
                f.create_dataset('image offset y', data=self.ROI_offset_y)
                f.create_dataset('gain', data=self.gain)
                f.create_dataset('time', data=ctime(time()))
                f.create_dataset('temperature', data=self.temperature)
                f.create_dataset('images', (N_frames, self.img_len),
                                 dtype=self.images_dtype,
                                 chunks=(1, self.img_len))
                f.create_dataset('timestamps_lab', (N_frames, ),
                                 dtype='float64')
                f.create_dataset('timestamps_camera', (N_frames, ),
                                 dtype='float64')
                f.create_dataset('frameIDs', (N_frames, ), dtype='int64')
        self.recording_filename = filename

    def record_dataset(self,
                       root='/mnt/data/',
                       name='test',
                       N_frames=256,
                       overwrite=False):
        self.recording_stop()
        sleep(1)
        self.queue.reset()
        self.recording_root = root
        self.recording_init(N_frames, name, overwrite)
        self.recording_start()
        print(
            f'avaiting trigger pulses. The name of the first chunk is {camera.recording_filename}'
        )

    def record_once(self, filename, N):
        """
        records a sequence of N frames and save them in filename hdf5 file.
        """
        from h5py import File
        from time import time
        N = 1  #temporary work around. extract only 1 frame and save it. Got rid of for loop and now reading -1 index instead of 0.
        raws = self.queue.dequeue(N)

        if raws.shape[0] > 0:
            with File(filename, 'a') as f:
                #for i in range(N):
                pointer = self.recording_pointer
                raw = raws[-1]  #raw = raws[i]
                tlab, tcam, frameID = self.extract_timestamp_image(raw)
                f['images'][pointer] = raw[:self.img_len]
                f['timestamps_lab'][pointer] = tlab
                f['timestamps_camera'][pointer] = tcam
                f['frameIDs'][pointer] = frameID
                self.recording_pointer += 1
        else:
            warn(
                f'{self.name}: got empty array from deque with rear value in the queue of {self.queue.rear}'
            )

    def recording_run(self):
        """
        records iamges to file in a loop.
        """
        from time import time, ctime
        from os import utime, rename
        from h5py import File
        while (self.recording):
            if self.recording_pointer == self.recording_Nframes:
                #create new file
                self.recording_chunk_pointer += 1
                if self.recording_chunk_pointer >= self.recording_chunk_maxpointer:
                    self.recording = False
                    break
                self.recording_pointer = 0
                rename(
                    self.recording_basefilename + '_' +
                    str(self.recording_chunk_pointer - 1) + '.tmpraw.hdf5',
                    self.recording_basefilename + '_' +
                    str(self.recording_chunk_pointer - 1) + '.raw.hdf5')
                f = File(
                    self.recording_basefilename + '_' +
                    str(self.recording_chunk_pointer - 1) + '.raw.hdf5', 'r')
                timestamp = f['timestamps_lab'][0]
                utime(
                    self.recording_basefilename + '_' +
                    str(self.recording_chunk_pointer - 1) + '.raw.hdf5',
                    (timestamp, timestamp))

                filename = self.recording_basefilename + '_' + str(
                    self.recording_chunk_pointer) + '.tmpraw.hdf5'
                Nframes = self.recording_Nframes
                self.recording_create_file(filename, Nframes)

            filename = self.recording_filename
            N = self.recording_N
            if (self.queue.length > N):
                self.record_once(filename=filename, N=N)
            else:
                sleep((N + 3) * 0.051)
        self.recording = False
        info(f'Recording Loop is finished')

    def recording_start(self):
        """
        a simple wrapper to start a recording_run loop in a separate thread.

        stops recording threads if such are active.
        resets queue to insure we save only new data.
        """
        from ubcs_auxiliary.multithreading import new_thread
        from time import time, sleep
        if self.recording:
            self.recording_stop()
            sleep(1)
        self.queue.reset()
        self.recording = True
        self.threads['recording'] = new_thread(self.recording_run)

    def recording_stop(self):
        """
        a wrapper that stops the recording loop
        """
        self.recording = False
        self.threads['recording'] = None

    def extract_timestamp_image(self, raw):
        """
        Extracts header information from the

        returns timestamp_lab,timestamp_cam,frameid
        """
        pointer = self.img_len
        header_img = raw[pointer:pointer + 64]
        timestamp_lab = self.binarr_to_number(header_img) / 1000000
        header_img = raw[pointer + 64:pointer + 128]
        timestamp_cam = self.binarr_to_number(header_img)
        header_img = raw[pointer + 128:pointer + 192]
        frameid = self.binarr_to_number(header_img)
        return timestamp_lab, timestamp_cam, frameid

    def binarr_to_number(self, vector):
        """
        converts a vector of bits into an integer.
        """
        num = 0
        from numpy import flip
        vector = flip(vector)
        length = vector.shape[0]
        for i in range(length):
            num += (2**(i)) * vector[i]
        return num

    def bin_array(self, num, m):
        """
        Converts a positive integer num into an m-bit bit vector
        """
        from numpy import uint8, binary_repr, array
        return array(list(binary_repr(num).zfill(m))).astype(uint8)
class FlirCamera():
    def __init__(self, name=None, system=None):
        from numpy import zeros, nan
        self.name = name
        self.system = system
        self.last_image_time = zeros((1, 20))
        self.recording_filename = f'camera_{name}.hdf5'
        self.recording_root = '/mnt/data/'
        self.recording_N = 1
        self.recording = False
        self.recording_pointer = 0
        self.threads = {}

    def init(self, serial_number, settings=1):
        from numpy import zeros, nan
        print('')
        print('-------------INITIALIZING NEW CAMERA-----------')
        import PySpin
        from circular_buffer_numpy.queue import Queue
        from circular_buffer_numpy.circular_buffer import CircularBuffer
        self.acquiring = False

        self.cam = self.find_camera(serial_number=serial_number)
        self.nodes = self.get_nodes()

        self.height = self.get_height()
        self.width = self.get_width()
        self.queue = Queue((620, self.height + 1, self.width), dtype='uint16')
        self.analysis_buffer = CircularBuffer(shape=(100, 20), dtype='float64')
        self.last_image_time_buffer = CircularBuffer(shape=(6000, 20),
                                                     dtype='float64')
        self.last_image_time_buffer.buffer = self.last_image_time_buffer.buffer * nan
        self.timestamp_buffer = CircularBuffer(shape=(6000, 1),
                                               dtype='float64')
        self.last_image = zeros((self.height + 1, self.width), dtype='uint16')
        self.set_lut_enable(False)
        self.set_gamma_enable(False)
        #self.set_gamma(0.5)
        self.set_autoexposure('Off')
        self.set_autogain('Off')

        self.configure_transport()
        try:
            self.cam.AcquisitionStop()
            print("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            print("Acquisition was already stopped")

        print('setting pixel format Mono11Packed')
        self.cam.PixelFormat.SetValue(PixelFormat_Mono12p)

        self.set_exposure_mode('Timed')
        self.exposure_time = 63000  #53500
        self.gain = 0
        self.black_level = 15
        self.background = zeros((self.height + 1, self.width))
        self.background[:self.height, :] = 15
        self.background_flag = True

        self.conf_acq_and_trigger(settings=settings)

    def close(sself):
        pass

    def kill(self):
        """
        """
        self.pause_acquisition()
        sleep(1)
        self.stop_acquisition()
        sleep(0.1)
        del self.cam
        self.system.ReleaseInstance()
        del self

    def reset_to_factory_settings(self):
        self.pause_acquisition()
        self.stop_acquisition()
        try:
            self.cam.AcquisitionStop()
            print("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            print("Acquisition was already stopped")
        self.cam.UserSetSelector.SetValue(PySpin.UserSetSelector_Default)
        self.cam.UserSetLoad()

    def configure_transport(self):
        cam = self.cam
        # Configure Transport Layer Properties
        cam.TLStream.StreamBufferHandlingMode.SetValue(
            PySpin.StreamBufferHandlingMode_OldestFirst)
        cam.TLStream.StreamBufferCountMode.SetValue(
            PySpin.StreamBufferCountMode_Manual)
        cam.TLStream.StreamBufferCountManual.SetValue(10)
        print(
            f"Buffer Handling Mode: {cam.TLStream.StreamBufferHandlingMode.GetCurrentEntry().GetSymbolic()}"
        )
        print(
            f"Buffer Count Mode: {cam.TLStream.StreamBufferCountMode.GetCurrentEntry().GetSymbolic()}"
        )
        print(
            f"Buffer Count: {cam.TLStream.StreamBufferCountManual.GetValue()}")
        print(
            f"Max Buffer Count: {cam.TLStream.StreamBufferCountManual.GetMax()}"
        )

    def deinit(self):
        self.stop_acquisition()
        self.cam.DeInit()

    def find_camera(self, serial_number=None):
        """
        looks for all cameras connected and returns cam object
        """
        cam = None
        cam_list = self.system.GetCameras()
        num_cameras = cam_list.GetSize()
        print(f'found {num_cameras} cameras')
        for i, cam in enumerate(cam_list):
            sn = cam.TLDevice.DeviceSerialNumber.GetValue()
            print(f'sn = {sn}')
            if serial_number == sn:
                break
        cam_list.Clear()
        return cam

    def get_all_cameras(self):
        cam_list = self.system.GetCameras()
        num_cameras = cam_list.GetSize()
        print(f'found {num_cameras} cameras')
        cameras = []
        for i, cam in enumerate(cam_list):
            sn = cam.TLDevice.DeviceSerialNumber.GetValue()
            print(f'sn = {sn}')
            cameras.append(sn)
        cam_list.Clear()
        return cameras

    def get_nodes(self):
        import PySpin
        self.cam.Init()
        # Retrieve GenICam nodemap
        nodemap = self.cam.GetNodeMap()
        self.nodemap = nodemap
        nodes = {}
        nodes['auto_gain'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('GainAuto'))
        nodes['pixel_format'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('PixelFormat'))
        nodes['gain'] = PySpin.CEnumerationPtr(nodemap.GetNode('Gain'))
        nodes['acquisition_mode'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('AcquisitionMode'))
        nodes['exposure_time'] = PySpin.CEnumerationPtr(
            nodemap.GetNode('ExposureTime'))
        return nodes

    def get_background(self):
        from numpy import mean
        self.background = mean(self.queue.buffer, axis=0)

    def get_image(self):
        from numpy import right_shift, nan, zeros
        self.last_image *= 0
        if self.acquiring:
            self.last_image_time[0, 3] = time()
            image_result = self.cam.GetNextImage()
            timestamp = image_result.GetTimeStamp()
            self.last_image_result = image_result
            self.last_image_time[0, 4] = time()
            # Getting the image data as a numpy array
            image_data = image_result.Convert(PixelFormat_Mono16).GetNDArray()
            image_data = right_shift(image_data, 4)
            self.last_image_time[0, 5] = time()
            image_result.Release()
            self.last_image_time[0, 6] = time()
        else:
            print('No Data in get image')
            image_data = zeros((self.height, self.width))
        self.last_image_time[0, 7] = time()
        self.last_image[0:self.height, :] = image_data
        self.last_image[self.height, :64] = self.get_image_header(value=int(
            time() * 1000000),
                                                                  length=64)
        self.last_image[self.height,
                        64:128] = self.get_image_header(value=timestamp,
                                                        length=64)
        self.last_image_time[0, 8] = time()
        return self.last_image

    def get_image_header(self, value=None, length=4096):
        from time import time
        from numpy import zeros
        from ubcs_auxiliary.numerical import bin_array
        arr = zeros((1, length))
        if value is None:
            t = int(time() * 1000000)
        else:
            t = value
        arr[0, :64] = bin_array(t, 64)
        return arr

    def binarr_to_number(self, arr):
        num = 0
        from numpy import flip
        arr = flip(arr)
        length = arr.shape[0]
        for i in range(length):
            num += (2**(i)) * arr[i]
        return num

    def bin_array(num, m):
        from numpy import uint8, binary_repr, array
        """Convert a positive integer num into an m-bit bit vector"""
        return array(list(binary_repr(num).zfill(m))).astype(uint8)

    def run_once(self):
        if self.acquiring:
            img = self.get_image()
            self.last_image_time[0, 9] = time()
            data = img.reshape(1, img.shape[0], img.shape[1])
            self.last_image_time[0, 10] = time()
            self.queue.enqueue(data)
            self.last_image_time[0, 11] = time()
            self.last_image_time_buffer.append(self.last_image_time)
            self.last_image_time[0, 12] = time()

    def run(self):
        while self.acquiring:
            self.run_once()

    def start_thread(self):
        from ubcs_auxiliary.multithreading import new_thread
        if not self.acquiring:
            self.start_acquisition()
            self.threads['acquisition'] = new_thread(self.run)

    def stop_thread(self):
        if self.acquiring:
            self.stop_acquisition()

    def resume_acquisition(self):
        """
        """
        from ubcs_auxiliary.multithreading import new_thread
        if not self.acquiring:
            self.acquiring = True
            self.threads['acquisition'] = new_thread(self.run)

    def pause_acquisition(self):
        """
        """
        self.acquiring = False

    def start_acquisition(self):
        """
        a wrapper to start acquisition of images.
        """
        self.acquiring = True
        self.cam.BeginAcquisition()

    def stop_acquisition(self):
        """
        a wrapper to stop acquisition of images.
        """
        self.acquiring = False
        try:
            self.cam.EndAcquisition()
            print("Acquisition ended")
        except PySpin.SpinnakerException as ex:
            print("Acquisition was already ended")

    def get_black_level(self):
        self.cam.BlackLevelSelector.SetValue(0)
        all = self.cam.BlackLevel.GetValue() * 4095 / 100
        self.cam.BlackLevelSelector.SetValue(1)
        analog = self.cam.BlackLevel.GetValue() * 4095 / 100
        self.cam.BlackLevelSelector.SetValue(2)
        digital = self.cam.BlackLevel.GetValue() * 4095 / 100
        self.cam.BlackLevelSelector.SetValue(0)
        return {'all': all, 'analog': analog, 'digital': digital}

    def set_black_level(self, value):
        """
        """
        self.cam.BlackLevelSelector.SetValue(0)
        self.cam.BlackLevel.SetValue(value * 100 / 4095)

    black_level = property(get_black_level, set_black_level)

    def get_temperature(self):
        """
        """
        temp = self.cam.DeviceTemperature.GetValue()
        return temp

    temperature = property(get_temperature)

    def get_fps():
        return nan

    def set_fps(value):
        pass

    fps = property(get_fps, set_fps)

    def get_gain(self):
        return self.cam.Gain.GetValue()

    def set_gain(self, value):
        if value >= self.cam.Gain.GetMax():
            value = self.cam.Gain.GetMax()
        elif value < self.cam.Gain.GetMin():
            value = self.cam.Gain.GetMin()
        self.cam.Gain.SetValue(value)

    gain = property(get_gain, set_gain)

    def get_autogain(self):
        if self.cam is not None:
            value = self.cam.GainAuto.GetValue()
            if value == 0:
                return 'Off'
            elif value == 1:
                return 'Once'
            elif value == 2:
                return 'Continuous'
        else:
            return None

    def set_autogain(self, value):
        node = self.nodes['auto_gain']
        off = node.GetEntryByName("Off")
        once = node.GetEntryByName("Once")
        continuous = node.GetEntryByName("Continuous")
        if value == 'Off':
            node.SetIntValue(off.GetValue())
        elif value == 'Once':
            node.SetIntValue(once.GetValue())
        elif value == 'Continuous':
            node.SetIntValue(continuous.GetValue())

    autogain = property(get_autogain, set_autogain)

    def get_serial_number(self):
        import PySpin
        device_serial_number = PySpin.CStringPtr(
            self.nodemap_tldevice.GetNode('DeviceSerialNumber'))
        return device_serial_number

    def get_acquisition_mode(self):
        node = self.nodes['acquisition_mode']

    def set_acquisition_mode(self, value):
        node = self.nodes['acquisition_mode']
        continious = node.GetEntryByName("Continuous")
        single_frame = node.GetEntryByName("SingleFrame")
        multi_frame = node.GetEntryByName("MultiFrame")
        if value == 'Continuous':
            mode = continious
        elif value == 'SingleFrame':
            mode = single_frame
        elif value == 'MultiFrame':
            mode = multi_frame
        print(f'setting acquisition mode {value}')
        self.stop_acquisition()
        node.SetIntValue(mode)
        self.start_acquisition()

    def get_lut_enable(self):
        """
        """
        if self.cam is not None:
            result = self.cam.LUTEnable.GetValue()
        else:
            result = None
        return result

    def set_lut_enable(self, value):
        """
        """
        if self.cam is not None:
            self.cam.LUTEnable.SetValue(value)
        print(f'setting LUT enable {value}')

    lut_enable = property(get_lut_enable, set_lut_enable)

    def get_gamma_enable(self):
        """
        """
        if self.cam is not None:
            result = self.cam.GammaEnable.GetValue()
        else:
            result = None
        return result

    def set_gamma_enable(self, value):
        """
        """
        if self.cam is not None:
            self.cam.GammaEnable.SetValue(value)
        print(f'setting gamma enable {value}')

    gamma_enable = property(get_gamma_enable, set_gamma_enable)

    def get_gamma(self):
        if self.cam is not None:
            result = None
            #result = self.cam.Gamma.GetValue()
        else:
            result = None
        return result

    def set_gamma(self, value):
        """
        """
        if self.cam is not None:
            result = None
            #self.cam.Gamma.SetValue(value)
        print(f'setting gamma {value}')

    gamma = property(get_gamma, set_gamma)

    def get_height(self):
        if self.cam is not None:
            reply = self.cam.Height.GetValue()
        else:
            reply = nan
        return reply

    def get_width(self):
        if self.cam is not None:
            reply = self.cam.Width.GetValue()
        else:
            reply = nan
        return reply

    def set_exposure_mode(self, mode=None):
        from PySpin import ExposureMode_Timed, ExposureMode_TriggerWidth
        print(f'Setting up ExposureMode to {mode}')
        if self.cam is not None:
            if mode == "Timed":
                self.cam.ExposureMode.SetValue(ExposureMode_Timed)
            elif mode == "TriggerWidth":
                self.cam.ExposureMode.SetValue(ExposureMode_TriggerWidth)

    def set_autoexposure(self, value='Off'):
        from PySpin import ExposureAuto_Off, ExposureAuto_Continuous, ExposureAuto_Once
        if value == 'Off':
            self.cam.ExposureAuto.SetValue(ExposureAuto_Off)
        elif value == 'Once':
            self.cam.ExposureAuto.SetValue(ExposureAuto_Once)
        elif value == 'Continuous':
            self.cam.ExposureAuto.SetValue(ExposureAuto_Continuous)
            print(f'setting gamma enable {value}')

    def get_autoexposure(self, bool=False):
        value = self.cam.ExposureAuto.GetValue()
        if value == 0:
            return 'Off'
        elif value == 1:
            return 'Once'
        elif value == 2:
            return 'Continuous'
        else:
            return 'unknown'

    def set_exposure_time(self, value):
        if self.cam is not None:
            self.cam.ExposureTime.SetValue(value)
            self._exposure_time = value
        else:
            pass

    def get_exposure_time(self, ):
        if self.cam is not None:
            return self.cam.ExposureTime.GetValue()
        else:
            return nan
        self._exposure_time = value

    exposure_time = property(get_exposure_time, set_exposure_time)

    def set_pixel_format(self, value='Mono16'):
        self.cam.PixelFormat.SetIn


##### Acquisition Control
#####

    def trigger_now(self):
        """
        software trigger for camera
        """
        import PySpin
        self.cam.TriggerSoftware()

    def conf_acq_and_trigger(self, settings=1):
        """
        a collection of setting defined as appropriate for the selected modes of operation.

        settings 1 designed for external trigger mode of operation
        Acquisition Mode = Continuous
        Acquisition FrameRate Enable = False
        LUTEnable = False
        TriggerSource = Line 0
        TriggerMode = On
        TriggerSelector = FrameStart
        """
        import PySpin
        if self.cam is not None:
            if settings == 1:
                print('Acquisition and Trigger Settings: 1')
                print('setting continuous acquisition mode')
                self.cam.AcquisitionMode.SetIntValue(
                    PySpin.AcquisitionMode_Continuous)
                print('setting frame rate enable to False')
                self.cam.AcquisitionFrameRateEnable.SetValue(False)

                print('setting Look Up Table Enable to False')
                self.cam.LUTEnable.SetValue(False)

                print('setting TriggerSource Line0')
                self.cam.TriggerSource.SetValue(PySpin.TriggerSource_Line0)
                print('setting TriggerMode On')
                self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_On)

                print('setting TriggerSelector FrameStart')
                self.cam.TriggerSelector.SetValue(
                    PySpin.TriggerSelector_FrameStart)
                print('setting TriggerActivation RisingEdge')
                self.cam.TriggerActivation.SetValue(
                    PySpin.TriggerActivation_RisingEdge)
                print('setting TriggerOverlap ReadOnly ')
                self.cam.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut)

            elif settings == 2:
                print('Acquisition and Trigger Settings: 2')
                print('setting SingleFrame acquisition mode')
                self.cam.AcquisitionMode.SetIntValue(
                    PySpin.AcquisitionMode_SingleFrame)
                print('setting frame rate enable to False')
                self.cam.AcquisitionFrameRateEnable.SetValue(False)
                print('setting Look Up Table Enable to False')
                self.cam.LUTEnable.SetValue(False)

                print('setting frame rate enable to False')
                self.cam.AcquisitionFrameRateEnable.SetValue(False)
                print('setting TriggerMode On')
                self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_Off)

            elif settings == 3:
                print('Acquisition and Trigger Settings: 3 (software)')
                print('setting continuous acquisition mode')
                self.cam.AcquisitionMode.SetIntValue(
                    PySpin.AcquisitionMode_Continuous)

                print('setting Look Up Table Enable to False')
                self.cam.LUTEnable.SetValue(False)

                print('setting frame rate enable to True')
                self.cam.AcquisitionFrameRateEnable.SetValue(True)
                print('setting frame rate to 1')
                self.cam.AcquisitionFrameRate.SetValue(20.0)
                print('setting TriggerMode Off')
                self.cam.TriggerMode.SetIntValue(PySpin.TriggerMode_Off)
                print('setting TriggerSource Line0')
                self.cam.TriggerSource.SetValue(PySpin.TriggerSource_Line0)
                print('setting TriggerSource Software')
                self.cam.TriggerSource.SetValue(PySpin.TriggerSource_Software)

    def recording_init(self, filename=None, N_frames=1200, comments=''):
        from os.path import exists
        from h5py import File
        from time import time, sleep, ctime
        from numpy import zeros
        if filename is None:
            filename = self.recording_root + f'{self.name}_{comments}.raw.hdf5'
        if exists(filename):
            print('----WARNING----')
            print('The HDF5 file exists. Please delete it first!')
        else:
            print(f'The HDF5 was created. The file name is {filename}')
            with File(filename, 'a') as f:
                f.create_dataset('exposure time', data='trigger width')
                f.create_dataset('black level all',
                                 data=self.black_level['all'])
                f.create_dataset('black level analog',
                                 data=self.black_level['analog'])
                f.create_dataset('black level digital',
                                 data=self.black_level['digital'])
                f.create_dataset('gain', data=self.gain)
                f.create_dataset('time', data=ctime(time()))
                f.create_dataset('temperature', data=self.temperature)
                f.create_dataset('images', (N_frames, self.height, self.width),
                                 dtype='int16',
                                 chunks=(1, self.height, self.width))
                f.create_dataset('timestamps_lab', (N_frames, ),
                                 dtype='float64')
                f.create_dataset('timestamps_camera', (N_frames, ),
                                 dtype='float64')
            self.recording_filename = filename
        self.recording_N_frames = N_frames
        self.recording_pointer = 0
        self.recording_buffer = zeros(
            (self.recording_N, self.height, self.width))

    def record_once(self, filename, N):
        from h5py import File
        from numpy import copy, array

        self.recording_buffer = self.queue.dequeue(N)
        images = self.recording_buffer

        if images.shape[0] > 0:
            with File(filename, 'a') as f:
                for i in range(N):
                    pointer = self.recording_pointer
                    image = images[i]
                    tlab, tcam = self.extract_timestamp_image(image)
                    f['images'][pointer] = image[:self.height, :]
                    f['timestamps_lab'][pointer] = tlab
                    f['timestamps_camera'][pointer] = tcam
                    self.recording_pointer += 1

        else:
            print(
                f'{self.name}: got empty array from deque with rear value in the queue of {self.queue.rear}'
            )

    def recording_run(self):
        from h5py import File
        from time import time, ctime
        filename = self.recording_filename
        while (self.recording) and (self.recording_pointer <
                                    self.recording_N_frames):
            N = self.recording_N
            if self.queue.length > N:
                self.record_once(filename=filename, N=N)
            else:
                sleep((N + 3) * 0.051)
        self.recording = False
        print(ctime(time()),
              f'Recording of {self.recording_N_frames} is Finished')

    def recording_chunk_run(self, M):
        from h5py import File
        filename = self.recording_filename
        i = 0
        while (i < M) and self.recording:
            N = self.recording_N
            if self.queue.length > N:
                self.record_once(filename=filename, N=N)
                i += N
            else:
                sleep((N + 3) * self._exposure_time / 1000000)
        self.recording = False
        print(f'{self.recording_filename}: recording stopped')

    def recording_start(self):
        from ubcs_auxiliary.multithreading import new_thread
        self.recording = True
        new_thread(self.recording_run)

    def recording_stop(self):
        self.recording = False

    def recording_scratch(self):
        root = self.recording_root + 'scratch/'

        def full_speed():
            filename = self.recording_filename
            if images.shape[0] > 0:
                for i in range(N):
                    if self.recording_pointer >= self.recording_N_frames:
                        self.recording = False
                        break
                        print(
                            'Recording of {self.recording_N_frames} is Finished'
                        )
                    pointer = self.recording_pointer
                    image = images[i]
                    with File(filename, 'a') as f:
                        f['images'][pointer] = image[:self.height, :]
                        tlab, tcam = self.extract_timestamp_image(image)
                        f['timestamps_lab'][pointer] = tlab
                        f['timestamps_camera'][pointer] = tcam
                        #f['frameID'][pointer] = tcam
                        self.recording_pointer += 1

    def extract_timestamp_image(self, arr):
        """
        Takes array of images (length, rows, cols) and returns the header data

        The header information is located in the last row (row = 3000) of an image
        """
        header_arr = arr[-1, :64]
        timestamp_lab = self.binarr_to_number(header_arr) / 1000000
        header_arr = arr[-1, 64:128]
        timestamp_cam = self.binarr_to_number(header_arr)
        return timestamp_lab, timestamp_cam

    def binarr_to_number(self, vector):
        num = 0
        from numpy import flip
        vector = flip(vector)
        length = vector.shape[0]
        for i in range(length):
            num += (2**(i)) * vector[i]
        return num

    def bin_array(self, num, m):
        from numpy import uint8, binary_repr, array
        """Convert a positive integer num into an m-bit bit vector"""
        return array(list(binary_repr(num).zfill(m))).astype(uint8)
Beispiel #6
0
    def init(self, config_filename):
        from numpy import zeros, nan, ones
        info('')
        info('-------------INITIALIZING NEW CAMERA-----------')
        import PySpin
        from circular_buffer_numpy.queue import Queue

        config, flag = self.read_config_file(config_filename)
        self.pixel_format = config['pixel_format']

        self.ROI_width = int(config['ROI_width'])
        self.ROI_height = int(config['ROI_height'])
        self.ROI_offset_x = int(config['ROI_offset_x'])
        self.ROI_offset_y = int(config['ROI_offset_y'])

        self.reverseX = int(config['ROI_offset_y'])
        self.reverseY = int(config['ROI_offset_y'])
        self.rotate = int(config['rotate'])
        self.trigger = config['trigger']
        if 'binning_selector' in config.keys():
            self.binning_selector = config['binning_selector']
        if 'binning_horizontal_mode' in config.keys():
            self.binning_horizontal_mode = config['binning_horizontal_mode']
        if 'binning_vertical_mode' in config.keys():
            self.binning_vertical_mode = config['binning_vertical_mode']
        if 'binning_vertical' in config.keys():
            self.binning_vertical = int(config['binning_vertical'])
        if 'binning_horizontal' in config.keys():
            self.binning_horizontal = int(config['binning_horizontal'])

        nice = int(config['nice'])
        self.nice = nice
        info(f'setting up nice {nice}')
        if nice != 0:
            os.nice(nice)
        sn = str(config['serial_number'])
        self.init(serial_number=sn)
        self.start_thread()

        self.set_exposure_time(config['exposure_time'])

        self.cam = self.find_camera(serial_number=serial_number)

        for i in range(2):
            try:
                self.cam.AcquisitionStart()
                info("Acquisition Started")
            except PySpin.SpinnakerException as ex:
                info("Acquisition was already started")
            try:
                self.cam.AcquisitionStop()
                info("Acquisition ended")
            except PySpin.SpinnakerException as ex:
                info("Acquisition was already ended")

        # reset camera to default settings

        self.nodes = self.get_nodes()

        #Transport Configuration
        self.configure_transport()

        #Configure Image Format
        self.configure_image()

        #Analog Configuration
        self.conf_acq_and_trigger(settings=settings)

        self.height = self.get_height()
        self.width = self.get_width()
        if (self.pixel_format == 'mono8'):
            from lcp_video.analysis import get_mono12p_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12p_conversion_mask(self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif (self.pixel_format == 'mono12p'):
            from lcp_video.analysis import get_mono12p_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width * 1.5)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12p_conversion_mask(self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif (self.pixel_format == 'mono12packed'):
            from lcp_video.analysis import get_mono12packed_conversion_mask, get_mono12p_conversion_mask_8bit
            self.img_len = int(self.height * self.width * 1.5)
            self.images_dtype = 'uint8'
            self.conversion_mask = get_mono12packed_conversion_mask(
                self.img_len)
            self.conversion_mask8 = get_mono12p_conversion_mask_8bit(
                self.img_len)
        elif self.pixel_format == 'mono16' or self.pixel_format == 'mono12p_16':
            self.img_len = int(self.height * self.width)
            self.images_dtype = 'int16'
        self.queue = Queue(
            (self.queue_length, self.img_len + self.header_length),
            dtype=self.images_dtype)

        self.queue_frameID = Queue((self.queue_length, 2), dtype='float64')

        self.last_raw_image = zeros((self.img_len + self.header_length, ),
                                    dtype=self.images_dtype)

        from circular_buffer_numpy.circular_buffer import CircularBuffer
        self.hits_buffer = CircularBuffer((1350000, 2), dtype='float64')

        #Algorithms Configuration
        self.lut_enable = False
        self.gamma_enable = False
        self.autoexposure = 'Off'
        self.autogain = 'Off'

        try:
            self.cam.AcquisitionStop()
            info("Acquisition stopped")
        except PySpin.SpinnakerException as ex:
            info("Acquisition was already stopped")

        self.set_exposure_mode('Timed')
        self.exposure_time = 63000  #53500
        self.gain = 0
        self.black_level = 15

        self.image_threshold = zeros((self.height, self.width)) + 7

        self.image_median = zeros((self.height, self.width))
        self.image_median[:, :] = 15

        self.image_mean = zeros((self.height, self.width))
        self.image_mean[:, :] = 15
        self.image_mean_flag = True

        self.image_std = ones((self.height, self.width))
        self.image_std[:, :] = 0.8
        self.image_std_flag = True

        self.sigma_level = 6

        self.mask = zeros((self.height, self.width), dtype='bool')
        self.mask_flag = True

        self.last_frameID = -1
        self.num_of_missed_frames = 0
Beispiel #7
0
class Device():
    db = DataBase(root='TEMP', name='DI4108_DL')
    #: serial number, five character long string
    pr_serial_number = SavedProperty(db, 'Serial Number', '00000').init()
    pr_AI_channels = SavedProperty(db, 'Number of AI', 8).init()
    pr_DI_channels = SavedProperty(db, 'Number of DI', 1).init()
    pr_rate = SavedProperty(db, 'rate(Hz)', 4000).init()
    pr_baserate = SavedProperty(db, 'baserate(Hz)', 20000).init()
    pr_dec = SavedProperty(db, 'dec', 5).init()
    pr_DOI_config = SavedProperty(db, 'DIO config', '1111111').init()
    pr_DOI_set = SavedProperty(db, 'DIO set', '1111111').init()
    pr_packet_size = SavedProperty(db, 'packet size', 64).init()
    pr_packet_buffer_size = SavedProperty(db, 'pr_packet_buffer_size',
                                          1000).init()
    pr_os_buffer = SavedProperty(db, 'os_buffer', 12800).init()
    pressure_sensor_offset = SavedProperty(
        db, 'pressure_sensor_offset',
        [69.5595, 65.562, 68.881375, 84.2195, 86.96075, 17.248, 17.322, 0
         ]).init()  # value read at atmoshperic pressure
    pg_period = SavedProperty(db, 'pg_period', 5.0).init()
    pg_pre_pulse_width = SavedProperty(db, 'pg_pre_pulse_width', 0.1).init()
    pg_depre_pulse_width = SavedProperty(db, 'pg_depre_pulse_width',
                                         0.1).init()
    pg_delay_width = SavedProperty(db, 'pg_delay_width', 0.5).init()
    trigger_mode = 0
    DIO_default = 126

    def __init__(self):
        self.name = 'DI4108_DL'
        self.device_info = {}
        self.device_info['empty'] = 'empty'
        self.task_name_dict = {}
        self.task_name_dict['empty'] = 'empty'
        self.pr_rate = (self.pr_baserate) / self.pr_dec
        self.pr_buffer_size = (int(self.pr_packet_size * self.pr_rate), 10)
        self.queue = Queue(shape=self.pr_buffer_size, dtype='int16')
        self.OverflowFlag = False

        self.io_push_queue = None
        self.io_put_queue = None

        self.curr_dio = 127
        self.user_set_dio = self.curr_dio

        self.run_once_counter = 0

        self.threads = {}

    def first_time_setup(self):
        """
        set control variables to factory settings
        """
        self.pr_AI_channels = 8
        self.pr_DI_channels = 1
        self.pr_packet_size = 128
        self.pr_baserate = 20000
        self.pr_dec = 5
        self.pr_rate = self.pr_baserate * 1.0 / self.pr_dec
        self.pr_DOI_config = '1111111'  #all outputs
        self.pr_DOI_set = '1111111'  #all high
        self.pressure_sensor_offset = [
            69.5595, 65.562, 68.881375, 84.2195, 86.96075, 17.248, 17.322, 0
        ]

    def bind_driver(self, driver=None):
        """
        bind driver to device instance
        """
        self.driver = driver

    def _set_priority(self):
        import traceback
        import platform  #https://stackoverflow.com/questions/110362/how-can-i-find-the-current-os-in-python
        p = psutil.Process(os.getpid(
        ))  #source: https://psutil.readthedocs.io/en/release-2.2.1/
        # psutil.ABOVE_NORMAL_PRIORITY_CLASS
        # psutil.BELOW_NORMAL_PRIORITY_CLASS
        # psutil.HIGH_PRIORITY_CLASS
        # psutil.IDLE_PRIORITY_CLASS
        # psutil.NORMAL_PRIORITY_CLASS
        # psutil.REALTIME_PRIORITY_CLASS
        try:
            if platform.system() == 'Windows':
                p.nice(psutil.REALTIME_PRIORITY_CLASS)
            elif platform.system() == 'Linux':  #linux FIXIT
                p.nice(
                    -20
                )  # nice runs from -20 to +12, where -20 the most not nice code(highest priority)
        except:
            error(trace.format_exc())
        self.proccess = p

    def init(self):
        """
        initialize the DL program
        """
        if self.driver is not None:
            self.driver.init()
            self.device_info = {
                **self.driver.get_hardware_information(),
                **self.device_info
            }
            self.stop()
            self.config_DL(baserate=self.pr_baserate,
                           dec=self.pr_dec,
                           DOI_config=self.pr_DOI_config,
                           DOI_set=self.pr_DOI_set)
        else:
            warning(
                'The driver object in the device _init() is {}'.format(driver))

    def start(self):
        """
        Create a new thread and submits self.run for execution

        Parameters
        ----------

        Returns
        -------

        Examples
        --------
        >>> device.start()
        """
        from ubcs_auxiliary.threading import new_thread
        self.threads['running'] = new_thread(self.run)

    def stop(self):
        """
        Orderly stop of the device code.
        - stops data acquisiion
        - erases all data from USB buffers
        - set digital IO to all high
        - closes usb port connection

        Parameters
        ----------

        Returns
        -------

        Examples
        --------
        >>> device.stop()
        """
        self.running = False
        self.driver.stop_scan()
        self.driver.flush()
        self.set_DIO('1111111')  # turns all valves off
        self.driver.close_port()

    def kill(self):
        """
        Orderly self-destruction. kills all threads and deletes the instance.

        Parameters
        ----------

        Returns
        -------

        Examples
        --------
        >>> device.kill()
        """
        self.stop()
        del self

    def config_DL(self,
                  baserate=None,
                  dec=None,
                  DOI_config=None,
                  DOI_set=None):
        """
        configure analog and digital channels, and rate via baserate and dec.

        Parameters
        ----------
        value :: string

        Returns
        -------

        Examples
        --------
        >>> device.config_DL(baserate = 20000, dec = 5, DOI_config = '1111111',DOI_set = '1111111')
        """
        debug('DL: config DL start')
        self.driver.config_channels(baserate=baserate,
                                    dec=dec,
                                    conf_digital=int(DOI_config, 2),
                                    set_digital=int(DOI_set, 2))
        debug('DL: config DL end')

    def config_DIO(self, value='00000000'):
        """
        configure direction of digital IOs. It takes a string with 8 characters, '0' or '1' where
        '0' -
        '1' -

        Parameters
        ----------
        value :: string

        Returns
        -------

        Examples
        --------
        >>> device.config_DIO('00000000')
        """
        if self.running:
            driver.config_digital(int(string, 2))
            reply = None
        else:
            reply = driver.config_digital(int(string, 2), echo=True)
        return reply

    def set_DIO(self, value='00000000'):
        """
        set digital input/output state

        Parameters
        ----------
        value :: string

        Returns
        -------

        Examples
        --------
        >>> device.DIO = 127
        """
        if isinstance(value, str):
            value = int(value, 2)
        self.driver.set_digital(value)
        self.io_push({'dio': value})
        info('set DIO inside device daq library')

    def set_outside_DIO(self, value='00000000'):
        """
        sets digital input/output state

        Parameters
        ----------
        value :: string

        Returns
        -------

        Examples
        --------
        >>> device.DIO = 127
        """
        if isinstance(value, str):
            value = int(value, 2)
        self.driver.set_digital(value)
        info('set DIO inside device daq library')

    def get_DIO(self):
        """
        get digital state from data queue
        """
        return int(self.queue.peek_last_N(3)[-1, 9])

    DIO = property(get_DIO, set_DIO)

    ### Advance function

    def run(self):
        """
        This is a main fuction that will execute run_once function on the while running loop. Usually it gets submitted to a separate thread.

        This function collects data and puts it in the Ring Buffer.
        It is run in a separate thread(See main priogram)

        Parameters
        ----------

        Returns
        -------

        Examples
        --------
        >>> device.run()
        """
        from time import strftime, localtime, time
        info('Measurement thread has started')
        self.driver.readall()
        self.running = True
        self.driver.start_scan()
        while self.running:
            self.run_once()
        info('data acquisition thread has stopped')

    def run_once(self):
        """
        the repeated block executed in while running loop in the main run() thread

        Parameters
        ----------

        Returns
        -------

        Examples
        --------
        >>> device.run_once()
        """
        self.run_once_counter += 1
        from numpy import array
        data, flag = (self.driver.get_readings(
            points_to_read=self.pr_packet_size))
        self.data = data
        debug(f'data from one reading cycle of the driver {data.shape}')
        debug(
            f'the length of pressure sensor is  offset{len(self.pressure_sensor_offset)}'
        )
        pressure_sensor_offset = array(self.pressure_sensor_offset)
        if flag:
            for i in range(8):
                try:
                    data[:, i] = data[:, i] - pressure_sensor_offset[i]
                except:
                    info('run_once')
                    error(traceback.format_exc())
            data[:, 8] = self.run_once_counter
            self.queue.enqueue(data)

        else:
            info('buffer overflow')
            self.running = False

    #####Auxiliary functions
    def parse_binary(self, value=0):
        """
        takes an integer and converts it to 8 bit representation as an array.
        If float number is passed, it will be converted to int.
        """
        from numpy import arange, ndarray, nan
        value = int(value)
        binary = format(value, '#010b')
        arr = arange(7)
        for i in range(7):
            arr[i] = binary[9 - i]
        return arr

    def unparse_binary(self, arr=array([1, 1, 1, 1, 1, 1, 1])):
        """
        takes an integer and converts it to 8 bit representation as an array.
        If float number is passed, it will be converted to int.
        """
        from numpy import arange, ndarray, nan
        integer = 0
        for i in range(len(arr)):
            integer += arr[i] * 2**(i)
        return integer

    def set_pressure_sensor_offset(self, dt=3):
        """
        set pressure sensor offset
        """
        # wait for dt seconds
        # calculated offset and standard deviation
        # assisgn first 8 mean values(analog values) to
        # self.pressure_sensor_offset
        from time import sleep
        sleep(dt)
        freq = int(self.pr_rate)
        offsets = self.queue.peek_last_N(dt * freq).mean(axis=0)
        stds = self.queue.peek_last_N(dt * freq).std(axis=0)
        info('Pressure sensors offsets are %r and errors are %r ' %
             (offsets, stds))
        self.pressure_sensor_offset = offsets[:8]

    ### Input-Output controller section
    def io_push(self, io_dict=None):
        """
        a wrapper that takes care of write command to the io module

        Parameters
        ----------
        io_dict :: dictionary
            a string name of the variable

        Returns
        -------

        Examples
        --------
        >>> self.io_push()
        """
        if self.io_push_queue is not None:
            self.io_push_queue.put(io_dict)

    def io_pull(self, io_dict):
        """
        a wrapper that takes care of 'read' command in the io module

        Parameters
        ----------
        io_dict :: dictionary
            a key-value pairs
        Returns
        -------

        Examples
        --------
        >>> self.io_pull(io_dict = {'key':'value'})
        """
        if self.io_pull_queue is not None:
            for key, value in io_dict.items:
                info(f'received update to {key} to change to {value}')