# ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Module authors: # Paul M. Neves # ***************************************************************************** from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, IntRange,\ IDLE, BUSY, WARN, ERROR, Drivable, BoolType, Attached from ast import literal_eval class RP100IO(StringIO): """communication with RP100""" end_of_line = '\n' #wait_before = 0.05 identification = [('*IDN?', r'Razorbill,.*')] class VoltageChannel(HasIO, Drivable): """a voltage output with loop""" temp = Attached() # define the communication class for automatic creation of the IO module ioClass = RP100IO # internal property to configure the channel channel = Property('the voltage channel', datatype=IntRange(1,2)) # modifying a property of inherited parameters (unit is propagated to the FloatRange datatype) value = Parameter('output voltage', FloatRange(-210, 210, unit='V'), readonly=True) target = Parameter('target voltage', FloatRange(-210, 210, unit='V'), readonly=False) meas_voltage = Parameter('measured output voltage', FloatRange(-250, 250, unit='V'), readonly=True) meas_current = Parameter('measured output current', FloatRange(-0.007, 0.007, unit='A'), readonly=True) max_target = Parameter('max. target', FloatRange(0, 210, unit='V'), readonly=False) min_target = Parameter('max. target', FloatRange(-210, 0, unit='V'), readonly=False) slew_rate = Parameter('voltage slew rate', FloatRange(0.1e-3, 100e3, unit='V/s'), readonly=False) output_state = Parameter('output on or off', BoolType(), readonly=False) def doPoll(self): super().doPoll() # calculate temperature dependent voltage limits temp = self.temp.target if temp > 250: self.max_target = 120 self.min_target = -20 elif temp >= 100: self.max_target = 120 self.min_target = -50 + (temp-100)/5 elif temp >= 10: self.max_target = 200 - 8*(temp-10)/9 self.min_target = -200 + 5*(temp-10)/3 elif temp < 10: self.max_target = 200 self.min_target = -200 # if the current voltage exceeds these limits, reduce voltage to max/min if self.target > self.max_target: self.write_target(self.max_target) if self.target < self.min_target: self.write_target(self.min_target) def read_value(self): # using the inherited HasIO.communicate method to send a command and get the reply reply = self.communicate(f'SOUR{self.channel}:VOLT:NOW?') return float(reply) def read_status(self): while 1: code, text = literal_eval(self.communicate(f'SYST:ERR?')) if code == 0: break self.log.warning('got error %d %s', code, text) return IDLE, '' def read_target(self): # read back the target value target = float(self.communicate(f'SOUR{self.channel}:VOLT?')) return target def write_target(self, target): # write here the target to the hardware if target > self.max_target: target = self.max_target self.log.warning('Attempted to set voltage above maximum allowed voltage. Setting to max allowed instead.') if target < self.min_target: target = self.min_target self.log.warning('Attempted to set voltage below minimum allowed voltage. Setting to min allowed instead.') self.communicate(f'SOUR{self.channel}:VOLT {target};*OPC?') return self.read_target() # return the read back value def read_slew_rate(self): return float(self.communicate(f'SOUR{self.channel}:VOLT:SLEW?')) def write_slew_rate(self, slew_rate): self.communicate(f'SOUR{self.channel}:VOLT:SLEW {slew_rate};*OPC?') return self.read_slew_rate() def read_output_state(self): return bool(self.communicate(f'OUTP{self.channel}?')) def write_output_state(self, output_state): self.communicate(f'OUTP{self.channel} {int(output_state)};*OPC?') return self.read_slew_rate() def read_meas_voltage(self): return float(self.communicate(f'MEAS{self.channel}:VOLT?')) def read_meas_current(self): return float(self.communicate(f'MEAS{self.channel}:CURR?'))