Example #1
0
def converge_scalar_tolerance(dmm,
                              funcgen,
                              set_point,
                              tolerance,
                              limit_amplitude=None,
                              settle_number=1,
                              attempts=5):
    p = LinearScalarControl(funcgen.amplitude_ch1)
    p.set_point(set_point)
    settle_cnt = 0
    for _ in range(attempts):
        test_val = dmm.measurement()
        if test_val > 1e10:
            raise InstrumentError(
                "Measurement outside the specified dmm range")
        # Test in range
        if set_point * (1 - tolerance) <= test_val <= set_point * (1 +
                                                                   tolerance):
            settle_cnt += 1
        else:
            settle_cnt = 0
        if settle_cnt >= settle_number:
            return
        # Get the control value from controller
        contr_val = p.update(test_val)
        # Put the control value into the kwargs for the control function
        if contr_val >= limit_amplitude:
            raise InstrumentError(
                "Converge function value {}Vpp exceeded the limit set {}Vpp".
                format(contr_val, limit_amplitude))
        funcgen.amplitude_ch1 = contr_val
    raise InstrumentError("Could not converge in {} attempts".format(attempts))
Example #2
0
 def get_cbus_pins(self):
     try:
         self.cmd_status.value = ftdI2xx.FT_SetBitMode(
             self.handle, UCHAR(0), BIT_MODE.FT_BITMODE_CBUS_BITBANG)
         if self.cmd_status.value != FT_STATUS.FT_OK.value:
             raise InstrumentError("FT_SetBitMode failed")
         data_bus = UCHAR()
         self.cmd_status.value = ftdI2xx.FT_GetBitMode(
             self.handle, ctypes.byref(data_bus))
         if self.cmd_status.value != FT_STATUS.FT_OK.value:
             raise InstrumentError("FT_GetBitMode failed")
     finally:
         self.cmd_status.value = ftdI2xx.FT_SetBitMode(
             self.handle, UCHAR(self.pin_value_mask), self.bit_mode)
     return data_bus.value
Example #3
0
    def measurements(self):
        if not self.mode:
            raise InstrumentError(
                "Please set DMM mode before taking a measurement!")

        with self.lock:
            return self._read_measurements()
Example #4
0
    def write(self, data):
        """
        The task should be in stopped state when calling write, it automatically starts the task through the
        DAQmxWriteDigitalLines call. When write is finished it is back in a stopped state
        :param data:
        :return:
        """
        self.init()
        try:
            if len(data) % self.io_length:
                raise ValueError("data must be a length divisible by {}".format(self.io_length))
        except TypeError as e:
            raise ValueError("data must be in an list divisible by {}".format(self.io_length)) from e
        if len(data) == self.io_length:
            # Sample clock only works for more than one sample so duplicate the sample
            data = list(data)
            data.extend(data)

        DAQmxCfgSampClkTiming(self.task, None, float64(self.frequency), DAQmx_Val_Rising, DAQmx_Val_FiniteSamps,
                              uInt64(int(len(data) // self.io_length)))

        try:
            data_arr = numpy.zeros((len(data)), uInt8)
            data_arr[:] = data

            written = int32()
            DAQmxWriteDigitalLines(self.task, int(len(data) // self.io_length), 1, -1,
                                   DAQmx_Val_GroupByScanNumber, data_arr, written, None)
            self.task_state = "running"
            DAQmxWaitUntilTaskDone(self.task, -1)
            if written.value != len(data) // self.io_length:
                raise InstrumentError("Values not written correctly")
        finally:
            self.stop()
Example #5
0
 def _is_error(self, silent=False):
     """
     Creates list of errors
     raise: InstrumentError if silent false
     return: list of errors
     """
     errors = []
     while True:
         code, msg = self._check_errors()
         if code != 0:
             errors.append((code, msg))
         else:
             break
     if errors:
         if silent:
             return errors
         else:
             raise InstrumentError(
                 "Error(s) Returned from DMM\n"
                 + "\n".join(
                     [
                         "Code: {}\nMessage:{}".format(code, msg)
                         for code, msg in errors
                     ]
                 )
             )
Example #6
0
 def trigger(self):
     if self._trigger_thread:
         self.clear()
         self._trigger_thread.join(10)
         if self._trigger_thread.is_alive():
             raise InstrumentError("Existing Trigger Event in Progress")
     self._trigger_thread = ExcThread(target=self._read)
     self._trigger_thread.start()
Example #7
0
 def _is_error(self, silent=False):
     code, msg = self._check_errors()
     if code != 0:
         if silent:
             return [(code, msg)]
         else:
             raise InstrumentError("Error Returned from PPS\n" +
                                   "Code: {}\nMessage:{}".format(code, msg))
Example #8
0
 def _read(self):
     try:
         return self.instrument.read()
     except VisaIOError as e:
         # TODO Write to log
         if e.error_code == VI_ERROR_TMO:
             raise InstrumentTimeOut("Instrument Timed out on read operation") from e
         raise InstrumentError("Unknown IO error from read operation") from e
Example #9
0
 def retrieve_waveform_data(self):
     self.instrument.write(":WAV:DATA?")
     time.sleep(0.2)
     data = self.read_raw()[:-1]  # Strip \n
     if data[0:1] != '#'.encode():
         raise InstrumentError("Pound Character missing in waveform data response")
     valid_bytes = data[int(data[1:2]) + 2:]  # data[1] denotes length value digits
     values = struct.unpack("%dB" % len(valid_bytes), valid_bytes)
     return values
Example #10
0
 def self_test(self):
     timeout = self.instrument.timeout
     try:
         self.instrument.timeout = 20000
         resp = self.instrument.query("*TST?")
         if "0" not in resp:
             raise InstrumentError("Failed Self Test")
     finally:
         self.instrument.timeout = timeout
Example #11
0
 def baud_rate(self, rate):
     try:
         self.cmd_status.value = ftdI2xx.FT_SetBaudRate(
             self.handle, DWORD(rate))
         if self.cmd_status.value != FT_STATUS.FT_OK.value:
             raise InstrumentError("FT_SetBaudRate failed")
         self._baud_rate = rate
     except:
         self._baud_rate = None
         raise
Example #12
0
 def _raise_if_error(self):
     errors = []
     while True:
         code, msg = self._check_errors()
         if code != 0:
             errors.append((code, msg))
         else:
             break
     if errors:
         raise InstrumentError("Error(s) Returned from DSO\n" +
                               "\n".join(["Code: {}\nMessage:{}".format(code, msg) for code, msg in errors]))
Example #13
0
 def write_bit_mode(self, mask, validate=False):
     """
         handle; gained from device info
         mask; value to write for the mask
             for BIT_MODE.FT_BITMODE_CBUS_BITBANG
             upper nibble is input (0) output (1)
             lower nibble is pin value low (0) high (1)
         bit_mode; Type BIT_MODE
     """
     self.cmd_status.value = ftdI2xx.FT_SetBitMode(self.handle, UCHAR(mask),
                                                   self.bit_mode)
     if self.cmd_status.value != FT_STATUS.FT_OK.value:
         raise InstrumentError("FT_SetBitMode failed")
     data_bus = UCHAR()
     if validate:
         self.cmd_status.value = ftdI2xx.FT_GetBitMode(
             self.handle, ctypes.byref(data_bus))
         if self.cmd_status.value != FT_STATUS.FT_OK.value:
             raise InstrumentError("FT_GetBitMode failed")
         return data_bus.value & self.pin_value_mask == mask & self.pin_value_mask
Example #14
0
    def _read(self):
        if not self._data_characteristics_set:
            self._set_data_characteristics()

        amount_in_rx_queue = DWORD()
        amount_in_tx_queue = DWORD()
        status = DWORD()
        self.cmd_status.value = ftdI2xx.FT_GetStatus(
            self.handle, ctypes.byref(amount_in_rx_queue),
            ctypes.byref(amount_in_tx_queue), ctypes.byref(status))
        if self.cmd_status.value != FT_STATUS.FT_OK.value:
            raise InstrumentError("FT_GetStatus failed")
        buffer = ctypes.create_string_buffer(amount_in_rx_queue.value)
        bytes_read = DWORD()
        self.cmd_status.value = ftdI2xx.FT_Read(self.handle,
                                                ctypes.byref(buffer),
                                                amount_in_rx_queue,
                                                ctypes.byref(bytes_read))
        if self.cmd_status.value != FT_STATUS.FT_OK.value:
            raise InstrumentError("FT_Read failed")
        return buffer
Example #15
0
 def read(self):
     self._trigger_thread.join(self._thread_timeout)
     if self._trigger_thread.is_alive():
         raise InstrumentError("Trigger thread failed to terminate")
     try:
         err = self._error_queue.get_nowait()
     except Empty:
         # no error in queue
         pass
     else:
         raise err
     return self._data
Example #16
0
    def init(self):
        if self.task_state == "":
            self.task = TaskHandle()
            DAQmxCreateTask(b"", byref(self.task))
            DAQmxCreateCITwoEdgeSepChan(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(), b"",
                                        float64(self.min_val), float64(self.max_val), DAQmx_Val_Seconds,
                                        self.first_edge_type,
                                        self.second_edge_type, b"")
            if self.source_terminal:
                tmp_data = c_char_p(self.source_terminal.encode())
                DAQmxSetCITwoEdgeSepFirstTerm(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(),
                                              tmp_data)
                if self.validate_terminals:
                    tmp_data = c_char_p("".encode())
                    DAQmxGetCITwoEdgeSepFirstTerm(self.task,
                                                  "{}/{}".format(self.device_name, self.counter_chan).encode(),
                                                  tmp_data,
                                                  uInt32(16))
                    if self.destination_terminal not in tmp_data.value.decode('utf-8'):
                        raise InstrumentError(
                            "Destination terminal is set to {}, should be /{}/{}".format(tmp_data.value.decode('utf-8'),
                                                                                         self.device_name,
                                                                                         self.destination_terminal))

            if self.destination_terminal:
                tmp_data = c_char_p(self.destination_terminal.encode())
                DAQmxSetCITwoEdgeSepSecondTerm(self.task, "{}/{}".format(self.device_name, self.counter_chan).encode(),
                                               tmp_data)
                if self.validate_terminals:
                    tmp_data = c_char_p("".encode())
                    DAQmxGetCITwoEdgeSepSecondTerm(self.task,
                                                   "{}/{}".format(self.device_name, self.counter_chan).encode(),
                                                   tmp_data,
                                                   uInt32(16))
                    if self.destination_terminal not in tmp_data.value.decode('utf-8'):
                        raise InstrumentError(
                            "Destination terminal is set to {}, should be /{}/{}".format(tmp_data.value.decode('utf-8'),
                                                                                         self.device_name,
                                                                                         self.destination_terminal))
            self.task_state = "init"
Example #17
0
 def _set_data_characteristics(self):
     if not [
             x for x in [self.word_length, self.stop_bits, self.parity]
             if x is None
     ]:
         self.cmd_status.value = ftdI2xx.FT_SetDataCharacteristics(
             self.handle, self.word_length, self.stop_bits, self.parity)
         if self.cmd_status.value != FT_STATUS.FT_OK.value:
             raise InstrumentError("FT_SetDatCharacteristics failed")
         self._data_characteristics_set = True
         return
     raise ValueError(
         "Please ensure that word length, stop bits and parity are set")
Example #18
0
    def write(self, data, size=None):
        if not self._data_characteristics_set:
            self._set_data_characteristics()

        if size is None:
            size = len(data)
        buffer = ctypes.create_string_buffer(bytes(data), size)
        bytes_written = DWORD()
        self.cmd_status.value = ftdI2xx.FT_Write(self.handle, buffer,
                                                 ctypes.sizeof(buffer),
                                                 ctypes.byref(bytes_written))
        if self.cmd_status.value != FT_STATUS.FT_OK.value:
            raise InstrumentError("FT_Write failed")
Example #19
0
 def read(self):
     self._trigger_thread.join(self._thread_timeout)
     if self._trigger_thread.is_alive():
         raise InstrumentError("Trigger thread failed to terminate")
     try:
         err = self._error_queue.get_nowait()
     except Empty:
         # no error in queue
         pass
     else:
         raise err
     # TODO: consider making this return self._data.value. We should return a python
     # float object, not a ctypes.c_double
     return self._data
Example #20
0
 def _write(self, data):
     try:
         if data:
             if isinstance(data, str):
                 self.instrument.write(data)
                 time.sleep(self.write_delay)
             else:
                 for itm in data:
                     self.instrument.write(itm)
                     time.sleep(self.write_delay)
             # self._is_error()
         else:
             raise ParameterError("Missing data in instrument write")
     except VisaIOError as e:
         # TODO Write to log
         raise InstrumentError("Unknown IO error from read operation") from e
Example #21
0
 def _is_error(self, silent=False):
     errors = []
     while True:
         code, msg = self._check_errors()
         if code != 0:
             errors.append((code, msg))
         else:
             break
     if errors:
         if silent:
             return errors
         else:
             raise InstrumentError(
                 "Error(s) Returned from FuncGen\n" + "\n".join([
                     "Code: {}\nMessage:{}".format(code, msg)
                     for code, msg in errors
                 ]))
Example #22
0
def converge_amplitude_scalar(dmm,
                              funcgen_or_ps,
                              set_point,
                              cur_amplitude,
                              mode=None,
                              frequency=None,
                              offset=0,
                              retries=None,
                              timeout=None,
                              settle_min=None,
                              settle_max=None,
                              settle_number=1,
                              limit_amplitude=None):
    """
    :param dmm:
        the instantiated class used as a dmm.
        The dmm should have the measurement type already set up
    :param funcgen_or_ps:
        the instantited class used as the control
        This can be a function generator or a programmable power supply
    :param set_point:
        The desired final resting value as measured through the dmm
    :param cur_amplitude:
        The current amplitude sent to the function generator or programmable power supply
    :param mode:
        Used for function generator and indicates the waveform
        eg. 'sin' or 'square'
    :param frequency:
        Used for function generator and indicates the waveform frequency
        eg. 1000
    :param offset:
        Used for function generator and indicates the waveform offset
        eg. 0.0
    :param retries:
    The amount of times the control is updated if it is not successful in converging first.
    Function will return True if all retries are attempted and settle parameters are not set
    Function will return False if all retries are attempted and settle parameters are set

    :param timeout:
    The amount of time the control will be updated if it is not successful in converging first or all retries attempted.
    Function will return True if timeout is reached and retries and settle parameters are not set
    Function will return False if timeout occurs and retries are set and settle parameters are set

    :param feedback_return_index:
    This is the index used from the return value.
    eg. dmm.measure()[0] would have feedback_return_index = 0
    eg. dmm.measure()["data"] would have feedback_return_index = 'data'

    :param settle_min:
    The minimum value that is considered to be at an acceptable settle point
    :param settle_max:
    The maximum value that is considered to be at an acceptable settle point
    :param settle_number:
    The number of consecutive measurements in a that are within settle_min <= value <= settle_max
    before the function returns True

    :return:
    True if converged
    False if not completed before retries or timeout
    Parameter error if parsed parameters are incompatible
    Calling functions exceptions are not handled
    """

    # Check if function gen
    # if issubclass(FuncGen, funcgen_or_ps):
    # if any(x is None for x in [mode, frequency, offset]):
    # raise MissingParameters("Need frequency and offset for function generator")
    # TODO Setup Timeout
    p = LinearScalarControl(cur_amplitude)
    p.set_point(set_point)
    settle_cnt = 0
    new_kwargs = {"frequency": frequency, "offset": offset}

    for _ in _range_gen(retries):
        test_val = dmm.measure()
        try:
            test_val = test_val[0]
        except TypeError:
            pass
        if test_val > 1e10:
            raise InstrumentError(
                "Measurement outside the specified dmm range")
        # Test in range
        if settle_min is not None and settle_max is not None:
            if settle_min <= test_val <= settle_max:
                settle_cnt += 1
            else:
                settle_cnt = 0
            if settle_cnt >= settle_number:
                return True
        # Get the control value from controller
        contr_val = p.update(test_val)
        # Put the control value into the kwargs for the control function
        if limit_amplitude and contr_val >= limit_amplitude:
            raise InstrumentError(
                "Converge function value {}Vpp exceeded the limit set {}Vpp".
                format(contr_val, limit_amplitude))
        new_kwargs.update(dict([('amplitude', contr_val)]))
        funcgen_or_ps.function(mode, **new_kwargs)
        if not (contr_val * 0.95 < funcgen_or_ps.amplitude_ch1 <=
                contr_val * 1.05):
            raise InstrumentError(
                "Amplitude {} set outside of instrument range {}".format(
                    contr_val, funcgen_or_ps.amplitude_ch1))
Example #23
0
 def _connect(self):
     self.cmd_status.value = ftdI2xx.FT_OpenEx(
         ctypes.c_char_p(self.ftdi_description),
         FLAGS.FT_OPEN_BY_DESCRIPTION, ctypes.byref(self.handle))
     if self.cmd_status.value != FT_STATUS.FT_OK.value:
         raise InstrumentError("FT_OpenEx failed")
Example #24
0
 def close(self):
     self.cmd_status.value = ftdI2xx.FT_Close(self.handle)
     if self.cmd_status.value != FT_STATUS.FT_OK.value:
         raise InstrumentError("FT_Close failed {}".format(
             self.cmd_status.value))
Example #25
0
 def _is_error(self):
     self.instrument.write("SYST:ERR?")
     time.sleep(self.write_delay)
     err_resp = self._read()
     if "no error" not in err_resp.lower():
         raise InstrumentError(err_resp)