class Itc503StreamInterface(StreamInterface):

    # Commands that we expect via serial during normal operation
    commands = {
        CmdBuilder("set_p").escape("P").float().eos().build(),
        CmdBuilder("set_i").escape("I").float().eos().build(),
        CmdBuilder("set_d").escape("D").float().eos().build(),
        CmdBuilder("get_p").escape("R8").eos().build(),
        CmdBuilder("get_i").escape("R9").eos().build(),
        CmdBuilder("get_d").escape("R10").eos().build(),
        CmdBuilder("get_temp_1").escape("R1").eos().build(),
        CmdBuilder("get_temp_2").escape("R2").eos().build(),
        CmdBuilder("get_temp_3").escape("R3").eos().build(),
        CmdBuilder("get_temp_sp").escape("R0").eos().build(),
        CmdBuilder("set_temp").escape("T").float().eos().build(),
        CmdBuilder("get_status").escape("X").eos().build(),
        CmdBuilder("set_ctrl").escape("C").int().eos().build(),
        CmdBuilder("set_mode").escape("A").int().eos().build(),
        CmdBuilder("set_ctrl_chan").escape("H").int().eos().build(),
        CmdBuilder("set_autopid_on").escape("L1").eos().build(),
        CmdBuilder("set_autopid_off").escape("L0").eos().build(),
        CmdBuilder("set_heater_maxv").escape("M").float().eos().build(),
        # No readback for max heater output
        CmdBuilder("set_heater_voltage").escape("O").float().eos().build(),
        CmdBuilder("get_heater_voltage").escape("R6").eos().build(),
        CmdBuilder("get_heater_percent").escape("R5").eos().build(),
        CmdBuilder("get_temp_error").escape("R4").eos().build(),
    }

    in_terminator = "\r"
    out_terminator = "\r"

    def handle_error(self, request, error):
        err_string = "command was: {}, error was: {}: {}\n".format(
            request, error.__class__.__name__, error)
        print(err_string)
        self.log.error(err_string)
        return err_string

    def set_p(self, p):
        self.device.p = float(p)
        return "P"

    def get_p(self):
        return "R{:.1f}".format(self.device.p)

    def set_i(self, i):
        self.device.i = float(i)
        return "I"

    def get_i(self):
        return "R{:.1f}".format(self.device.i)

    def set_d(self, d):
        self.device.d = float(d)
        return "D"

    def get_d(self):
        return "R{:.1f}".format(self.device.d)

    def get_temp_1(self):
        return "R{:.1f}".format(self.device.temperature_1)

    def get_temp_2(self):
        return "R{:.1f}".format(self.device.temperature_2)

    def get_temp_3(self):
        return "R{:.1f}".format(self.device.temperature_3)

    def set_temp(self, temp):
        self.device.temperature_sp = float(temp)
        return "T"

    def get_temp_sp(self):
        return "R{:.1f}".format(self.device.temperature_sp)

    def get_status(self):
        if self.device.report_sweep_state_with_leading_zero:
            format_string = "X0A{mode}C{ctrl}S{sweeping:02d}H{control_channel}L{autopid}"
        else:
            format_string = "X0A{mode}C{ctrl}S{sweeping:01d}H{control_channel}L{autopid}"

        return format_string.format(
            mode=self.device.mode,
            ctrl=self.device.control,
            sweeping=1 if self.device.sweeping else 0,
            control_channel=self.device.control_channel,
            autopid=1 if self.device.autopid else 0)

    def set_ctrl(self, ctrl):
        self.device.control = int(ctrl)
        return "C"

    def set_mode(self, mode):
        self.device.mode = int(mode)
        return "A"

    def set_ctrl_chan(self, chan):
        if not 1 <= int(chan) <= 3:
            raise ValueError("Invalid channel")
        self.device.control_channel = int(chan)
        return "H"

    def set_autopid_on(self):
        self.device.autopid = True
        return "L"

    def set_autopid_off(self):
        self.device.autopid = False
        return "L"

    def set_heater_voltage(self, manv):
        self.device.heater_voltage = float(manv)
        return "O"

    def get_heater_voltage(self):
        return "R{:.1f}".format(self.device.heater_voltage)

    def get_heater_percent(self):
        return "R{:.1f}".format(self.device.heater_percent)

    def set_heater_maxv(self, volts):
        raise ValueError("At ISIS, do not use this command!")

    def get_temp_error(self):
        return "R{:.1f}".format(
            abs(self.device.temperature_sp - self.device.temperature))
class Danfysik8500StreamInterface(CommonStreamInterface, StreamInterface):
    """
    Stream interface for a Danfysik model 8500.
    """

    in_terminator = "\r"
    out_terminator = "\n\r"

    protocol = 'model8500'

    # This is the address of the LOQ danfysik 8500
    PSU_ADDRESS = 75

    commands = CommonStreamInterface.commands + [
        CmdBuilder("set_current").escape("DA 0 ").int().eos().build(),
        CmdBuilder("get_current").escape("AD 8").eos().build(),
        CmdBuilder("set_address").escape("ADR ").int().eos().build(),
        CmdBuilder("get_address").escape("ADR").eos().build(),
        CmdBuilder("init_comms").escape("REM").eos().build(),
        CmdBuilder("init_comms").escape("UNLOCK").eos().build(),
        CmdBuilder("get_slew_rate").escape("R").arg(
            r"[1-3]", argument_mapping=int).eos().build(),
        CmdBuilder("set_slew_rate").escape("W").arg(
            r"[1-3]", argument_mapping=int).spaces().int().eos().build()
    ]

    @conditional_reply("device_available")
    @conditional_reply("comms_initialized")
    def get_status(self):
        """
        Respond to the get_status command (S1)
        """

        response = "{power_off}{pol_normal}{pol_reversed}{reg_transformer}{dac16}{dac17}{is_percent}{spare}"\
                   "{transistor_fault}{sum_interlock}{dc_overcurrent}{dc_overload}{reg_mod_fail}{prereg_fail}" \
                   "{phase_fail}{mps_waterflow_fail}{earth_leak_fail}{thermal_fail}{mps_overtemperature}" \
                   "{door_switch}{mag_waterflow_fail}{mag_overtemp}{mps_not_ready}{spare}".format(
                        spare=self.bit(False),
                        power_off=self.bit(not self.device.power),
                        pol_normal=self.bit(not self.device.negative_polarity),
                        pol_reversed=self.bit(self.device.negative_polarity),
                        reg_transformer=self.bit(False),
                        dac16=self.bit(False),
                        dac17=self.bit(False),
                        is_percent=self.bit(False),
                        transistor_fault=self.interlock("transistor_fault"),
                        sum_interlock=self.bit(len(self.device.active_interlocks) > 0),
                        dc_overcurrent=self.interlock("dc_overcurrent"),
                        dc_overload=self.interlock("dc_overload"),
                        reg_mod_fail=self.interlock("reg_mod_fail"),
                        prereg_fail=self.interlock("prereg_fail"),
                        phase_fail=self.interlock("phase_fail"),
                        mps_waterflow_fail=self.interlock("mps_waterflow_fail"),
                        earth_leak_fail=self.interlock("earth_leak_fail"),
                        thermal_fail=self.interlock("thermal_fail"),
                        mps_overtemperature=self.interlock("mps_overtemperature"),
                        door_switch=self.interlock("door_switch"),
                        mag_waterflow_fail=self.interlock("mag_waterflow_fail"),
                        mag_overtemp=self.interlock("mag_overtemp"),
                        mps_not_ready=self.bit(not self.device.power),
                    )

        assert len(
            response) == 24, "length should have been 24 but was {}".format(
                len(response))

        return response

    def set_address(self, value):
        self.device.set_address(value)

    @conditional_reply("comms_initialized")
    def get_address(self):
        return "{:03d}".format(self.address)

    @conditional_reply("comms_initialized")
    def get_slew_rate(self, dac_num):
        return self.device.get_slew_rate(dac_num)

    @conditional_reply("comms_initialized")
    def set_slew_rate(self, dac_num, slew_rate_value):
        self.device.set_slew_rate(dac_num, slew_rate_value)
示例#3
0
class Keithley2001StreamInterface(StreamInterface):

    in_terminator = "\r\n"
    out_terminator = "\n"

    _channel_readback_format = None

    commands = {
        # Commands used on setup
        CmdBuilder("get_idn").escape("*IDN?").eos().build(),
        CmdBuilder("reset_device").escape("*RST").eos().build(),
        CmdBuilder("set_buffer_source").escape(":DATA:FEED ").arg(
            "NONE|SENS1|CALC1").eos().build(),
        CmdBuilder("get_buffer_source").escape(":DATA:FEED?").eos().build(),
        CmdBuilder("set_buffer_egroup").escape(":DATA:EGR ").arg(
            "FULL|COMP").eos().build(),
        CmdBuilder("get_buffer_egroup").escape(":DATA:EGR?").eos().build(),
        CmdBuilder("set_continuous_initialization").escape(":INIT:CONT ").arg(
            "OFF|ON").eos().build(),
        CmdBuilder("get_continuous_initialization_status").escape(
            ":INIT:CONT?").eos().build(),
        CmdBuilder("get_elements").escape(":FORM:ELEM?").eos().build(),
        CmdBuilder("set_elements").escape(
            ":FORM:ELEM ").string().eos().build(),
        CmdBuilder("get_measurement_status").escape(
            ":STAT:MEAS:ENAB?").eos().build(),
        CmdBuilder("set_buffer_full_status").escape(
            ":STAT:MEAS:ENAB 512").eos().build(),
        CmdBuilder("get_service_request_status").escape("*SRE?").eos().build(),
        CmdBuilder("set_measure_summary_status").escape(
            "*SRE 1").eos().build(),
        CmdBuilder("reset_and_clear_status_registers").escape(
            ":STAT:PRES; *CLS").eos().build(),
        CmdBuilder("set_scan_count").escape(
            ":ARM:LAY2:COUN ").int().eos().build(),
        CmdBuilder("get_scan_count").escape(":ARM:LAY2:COUN?").eos().build(),
        CmdBuilder("get_scan_trigger").escape(":ARM:LAY2:SOUR?").eos().build(),

        # Reading a single channel
        CmdBuilder("set_read_channel").escape(":ROUT:CLOS (@").int().escape(
            ")").eos().build(),
        CmdBuilder("read_single_channel").escape(":READ?").eos().build(),

        # Reading from the buffer
        CmdBuilder("set_buffer_mode").escape(":DATA:FEED:CONT ").arg(
            "NEV|NEXT|ALW|PRET").eos().build(),
        CmdBuilder("get_buffer_mode").escape(":DATA:FEED:CONT?").eos().build(),
        CmdBuilder("clear_buffer").escape(":DATA:CLE").eos().build(),
        CmdBuilder("scan_channels").escape(":INIT").eos().build(),
        CmdBuilder("get_buffer_date").escape(":DATA:DATA?").eos().build(),

        # Setting up a scan
        CmdBuilder("set_measurement_scan_count").escape(":TRIG:COUN "
                                                        ).int().eos().build(),
        CmdBuilder("get_measurement_scan_count").escape(
            ":TRIG:COUN?").eos().build(),
        CmdBuilder("set_buffer_size").escape(
            ":DATA:POIN ").int().eos().build(),
        CmdBuilder("get_buffer_size").escape(":DATA:POIN?").eos().build(),
        CmdBuilder("set_scan_channels").escape(":ROUT:SCAN (@").arg(
            "[0-9,]+").escape(")").eos().build(),
        CmdBuilder("get_scan_channels").escape(":ROUT:SCAN?").eos().build(),

        # Error handling
        CmdBuilder("get_error").escape(":SYST:ERR?").eos().build()
    }

    def handle_error(self, request, error):
        self.log.error("An error occurred at request {}: {}".format(
            repr(request), repr(error)))
        print("An error occurred at request {}: {}".format(
            repr(request), repr(error)))

    # Commands used on setup
    @conditional_reply("_connected")
    def get_idn(self):
        """
        Returns the devices IDN string.

        Returns:
            string: The device's IDN.
        """

        idn = self._device.idn
        return idn

    @conditional_reply("_connected")
    def get_elements(self):
        """
        Returns the lists of elements of a reading in alphabetical order from the device.

        """
        elements = [
            element for element, value in self._device.elements.items()
            if value
        ]
        return ", ".join(elements)

    @conditional_reply("_connected")
    def set_elements(self, string):
        """
        Sets the elements a reading has.

        Args:
            string: String of comma separated elements of a reading. Valid elements are:
                READ, CHAN, RNUM, UNIT, TIME, STAT.
        """
        elements = {element.strip().upper() for element in string.split(",")}

        for element in elements:
            try:
                self._device.elements[element] = True
            except LookupError:
                self.log.error(
                    "Tried to set {} which is not a valid reading element.".
                    format(element))
                print("Tried to set {} which is not a valid reading element.".
                      format(element))

        self._generate_readback_format()

    @conditional_reply("_connected")
    def _generate_readback_format(self):
        """
        Generates the readback format for buffer readings.
        """
        readback_elements = []

        if self._device.elements["READ"]:
            readback_elements.append("{:.7E}")
            if self._device.elements["UNIT"]:
                readback_elements.append("{}")

        if self._device.elements["CHAN"]:
            readback_elements.append(",{:02d}")
            if self._device.elements["UNIT"]:
                readback_elements.append("INTCHAN")

        self._channel_readback_format = "".join(readback_elements)

    @conditional_reply("_connected")
    def reset_device(self):
        """
        Resets device.
        """
        self._device.reset_device()

    @conditional_reply("_connected")
    def set_buffer_source(self, source):
        """
        Sets the buffer source.
        """
        self._device.buffer.source = source

    @conditional_reply("_connected")
    def get_buffer_source(self):
        """
        Gets the buffer source.
        """
        return self._device.buffer.source

    @conditional_reply("_connected")
    def set_buffer_egroup(self, egroup):
        """
        Sets the buffer element group.
        """
        self._device.number_of_times_ioc_has_been_reset += 1

        self._device.buffer.egroup = egroup

    @conditional_reply("_connected")
    def get_buffer_egroup(self):
        """
        Gets the buffer element group.
        """
        return self._device.buffer.egroup

    @conditional_reply("_connected")
    def set_continuous_initialization(self, value):
        """
        Sets continuous scanning status to ON or OFF.

        Thus is called continuous initialization mode in the Keithley 2001 manual.

        Args:
            value (string): ON or OFF.
        """
        if value.upper() == "ON":
            self._device.continuous_initialisation_status = True
        elif value.upper() == "OFF":
            self._device.continuous_initialisation_status = False
        else:
            raise ValueError("Not a valid continuous initialisation mode")

    @conditional_reply("_connected")
    def get_continuous_initialization_status(self):
        """
        Gets the continuous scanning status.

        Thus is the continuous initialization mode in the Keithley 2001 manual.
        """
        status = "OFF"

        if self._device.continuous_initialisation_status:
            status = "ON"

        return status

    @conditional_reply("_connected")
    def set_buffer_full_status(self):
        """
        Sets the buffer full status of the status register to true.
        """

        self._device.status_register.buffer_full = True

    @conditional_reply("_connected")
    def set_measure_summary_status(self):
        """
        Sets the measurement summary status of the status register to true.
        """

        self._device.status_register.measurement_summary_status = True

    @conditional_reply("_connected")
    def get_measurement_status(self):
        """
        Returns the measurement status of the device.

        Returns:
            string: integer which represents the measurement status register status in bits.
        """

        status = 0
        if self._device.status_register.buffer_full:
            status += 512

        return str(status)

    @conditional_reply("_connected")
    def get_service_request_status(self):
        """
        Returns the measurement status of the device.

        Returns:
            string: integer which represents the service register status in bits.
        """
        status = 0
        if self._device.status_register.measurement_summary_status:
            status += 1

        return str(status)

    @conditional_reply("_connected")
    def reset_and_clear_status_registers(self):
        """
        Resets and clears the status registers of the device.
        """

        self._device.status_register.reset_and_clear()

    @conditional_reply("_connected")
    def set_scan_count(self, value):
        """
        Sets the scan count.

        Args:
            value (int): Number of times to scan.
        """
        self._device.scan_count = int(value)

    @conditional_reply("_connected")
    def get_scan_count(self):
        """
        Returns the number of times the device is set to scan.

        Returns:
            string: Number of times the device is set to scan.
        """
        return str(self._device.scan_count)

    @conditional_reply("_connected")
    def get_scan_trigger(self):
        """
        Returns the scan trigger type.

        Returns:
            string: Scan trigger mode. One of IMM, HOLD, MAN, BUS, TLINK, EXT, TIM.
        """

        return self._device.scan_trigger_type

    # Reading a single channel
    @conditional_reply("_connected")
    def set_read_channel(self, channel):
        """
        Sets the channels to read from in single read mode.

        Args:
            channel string): String representation of a channel number between 1 and 10.
        """
        self._device.close_channel(int(channel))

    @conditional_reply("_connected")
    def read_single_channel(self):
        """
        Takes a single reading from the closed channel on the device.

        Returns:
            string: Formatted string of channel data.
        """
        channel_data = self._device.take_single_reading()

        return "".join(self._format_buffer_readings(channel_data))

    # Setting up for a scan
    @conditional_reply("_connected")
    def set_buffer_mode(self, mode):
        """
        Sets the buffer mode.
        """
        self._device.buffer.mode = mode

    @conditional_reply("_connected")
    def get_buffer_mode(self):
        """
        Gets the buffer mode.
        """
        return self._device.buffer.mode

    @conditional_reply("_connected")
    def set_buffer_size(self, size):
        """
        Sets the buffer mode.
        """
        self._device.buffer.size = int(size)

    @conditional_reply("_connected")
    def get_buffer_size(self):
        """
        Gets the buffer mode.
        """
        return self._device.buffer.size

    @conditional_reply("_connected")
    def clear_buffer(self):
        """
        Clears the buffer.
        """
        self._device.buffer.clear_buffer()

    @conditional_reply("_connected")
    def set_scan_channels(self, channels):
        """
        Sets the channels to scan.

        Args:
            channels (string): Comma separated list of channel number to read from.
        """
        channels = channels.split(",")
        self._device.buffer.scan_channels = channels

    @conditional_reply("_connected")
    def get_scan_channels(self):
        """
        Returns the channels set to scan.

        Returns:
            string: comman separated list of channels set to scan
        """

        return "(@" + ",".join(self._device.buffer.scan_channels) + ")"

    @conditional_reply("_connected")
    def set_measurement_scan_count(self, value):
        """
        Sets the measurement scan count.

        Args:
            value (int): Number of times to trigger measurements.
        """
        self._device.measurement_scan_count = int(value)

    @conditional_reply("_connected")
    def get_measurement_scan_count(self):
        """
        Gets the measurement scan count.

        Returns:
            value (int): Number of times to trigger measurements
        """
        return str(self._device.measurement_scan_count)

    @conditional_reply("_connected")
    def scan_channels(self):
        """
        Sets the device to scan.

        """
        self._device.scan_channels()

    @conditional_reply("_connected")
    def get_buffer_date(self):
        """
        Returns the buffer data.

        Returns:
            list of strings: List of readings from channels.
        """

        return ",".join(
            map(self._format_buffer_readings, self._device.buffer.buffer))

    def _format_buffer_readings(self, reading):
        """
        Formats a reading.

        Args:
            reading: dictionary with keys
                "READ", "READ_UNIT", "CHAN"

        Returns:
            string: Buffer reading formatted depending on elements
        """
        formatted_buffer_reading = []

        if self._device.elements["READ"]:
            formatted_buffer_reading.append(reading["READ"])
            if self._device.elements["UNIT"]:
                formatted_buffer_reading.append(reading["READ_UNIT"])

        if self._device.elements["CHAN"]:
            formatted_buffer_reading.append(reading["CHAN"])

        return self._channel_readback_format.format(*formatted_buffer_reading)

    @conditional_reply("_connected")
    def get_error(self):
        """
        Returns the error code and message.

        Returns:
            (string): Returns the error string formed of
                error code, error message.
        """

        return ",".join(
            ["{}".format(self._device.error[0]), self._device.error[1]])
class KepcoStreamInterface(StreamInterface):

    in_terminator = "\r\n"
    out_terminator = "\r\n"

    commands = {
        CmdBuilder("write_voltage").escape("VOLT ").float().build(),
        CmdBuilder("read_actual_voltage").escape("MEAS:VOLT?").build(),
        CmdBuilder("read_actual_current").escape("MEAS:CURR?").build(),
        CmdBuilder("write_current").escape("CURR ").float().build(),
        CmdBuilder("read_setpoint_voltage").escape("VOLT?").build(),
        CmdBuilder("read_setpoint_current").escape("CURR?").build(),
        CmdBuilder("set_output_mode").escape("FUNC:MODE ").arg("VOLT|CURR").build(),
        CmdBuilder("read_output_mode").escape("FUNC:MODE?").build(),
        CmdBuilder("read_output_status").escape("OUTP?").build(),
        CmdBuilder("set_output_status").escape("OUTP ").arg("0|1").build(),
        CmdBuilder("get_IDN").escape("*IDN?").build(),
        CmdBuilder("set_control_mode").escape("SYST:REM ").arg("0|1").build(),
        CmdBuilder("reset").escape("*RST").build()
    }

    def handle_error(self,request, error):
        self.log.error("An error occurred at request" + repr(request) + ": " + repr(error))
        print("An error occurred at request" + repr(request) + ": " + repr(error))

    @if_connected
    def read_actual_voltage(self):
        return "{0}".format(self._device.voltage)

    @if_connected
    def read_actual_current(self):
        return "{0}".format(self._device.current)

    @if_connected
    @needs_remote_mode
    def write_voltage(self, voltage):
        self._device.setpoint_voltage = voltage

    @if_connected
    @needs_remote_mode
    def write_current(self, current):
        self._device.setpoint_current = current

    @if_connected
    def read_setpoint_voltage(self):
        return "{0}".format(self._device.setpoint_voltage)

    @if_connected
    def read_setpoint_current(self):
        return "{0}".format(self._device.setpoint_current)

    @if_connected
    @needs_remote_mode
    def set_output_mode(self, mode):
        self._device.output_mode = 0 if mode.startswith("CURR") else 1

    @if_connected
    def read_output_mode(self):
        return "{0}".format(self._device.output_mode)

    @if_connected
    @needs_remote_mode
    def set_output_status(self, status):
        self._device.output_status = status

    @if_connected
    def read_output_status(self):
        return "{0}".format(self._device.output_status)

    @if_connected
    def get_IDN(self):
        return "{0}".format(self._device.idn)

    @if_connected
    def set_control_mode(self, mode):
        if self._device.firmware <= 2.0:
            raise ValueError("No SYST:REM command available")
        else:
            mode = int(mode)
            if mode not in [0, 1]:
                raise ValueError("Invalid mode in set_control_mode: {}".format(mode))
            self._device.remote_comms_enabled = (mode == 1)

    @if_connected
    def reset(self):
        self._device.reset()