#!/usr/bin/env python # -*- coding: utf-8 -*- # ***************************************************************************** # 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: Oksana Shliakhtun # ***************************************************************************** import re from frappy.core import HasIO, Readable, Parameter, FloatRange, EnumType, StatusType, IDLE, ERROR, WARN def string_to_value(value): value_with_unit = re.compile(r'(\d+)([pnumkMG]?)') value, pfx = value_with_unit.match(value).groups() pfx_dict = {'p': 1e-12, 'n': 1e-9, 'u': 1e-6, 'm': 1e-3, 'k': 1e3, 'M': 1e6, 'G': 1e9} if pfx in pfx_dict: value = round(float(value) * pfx_dict[pfx], 12) return float(value) class HP_IO(HasIO): end_of_line = b'\n' identification = [('*IDN?', r'HEWLETT-PACKARD,34401A,0,.*')] class HP34401A(HP_IO): status = Parameter(datatype=StatusType(Readable, 'BUSY')) autorange = Parameter('autorange_on', EnumType('autorange', off=0, on=1), readonly=False, default=0) def comm(self, cmd): # read until \n string = f'{cmd}\n' n_string = string.encode() response = self.communicate(n_string) if response: return response response = self.communicate(n_string) return response if response else None def read_range(self, function): return self.comm(f'{function}:range?') def write_range(self, function, range): return self.comm(f'{function}:range {range}') def write_autorange(self, function): cmd = f'{function}:range:auto {"on" if self.autorange == 0 else "off"}' self.comm(cmd) return self.comm(f'{function}:range:auto?') def read_resolution(self, function): return self.comm(f'{function}:resolution?') def write_resolution(self, function, resolution): self.comm(f'{function}:resolution {resolution}') return self.comm(f'{function}:resolution?') def read_status(self): stb = int(self.comm('*STB?')) esr = int(self.comm('*ESR?')) if esr & (1 << 3): return ERROR, 'self-test/calibration/reading failed' if esr & (1 << 4): return ERROR, 'execution error' if esr & (1 << 5): return ERROR, 'syntax error' if esr & (1 << 2): return ERROR, 'query error' if stb & (1 << 3): return WARN, 'questionable data' if stb & (1 << 5): return WARN, 'standard event register is not empty' if stb & (1 << 6): return WARN, 'requested service' if any(stb & (1 << i) for i in range(3) or stb & (1 << 7)): return IDLE, '' if esr & (1 << 6): return IDLE, '' if esr & (1 << 7): return IDLE, '' if stb & (1 << 4): return IDLE, 'message available' if esr & (1 << 0): return IDLE, 'operation complete' if esr & (1 << 1): return IDLE, 'not used' class Voltage(HP34401A, Readable): value = Parameter('voltage', datatype=FloatRange(0.1, 1000), unit='V') range = Parameter('voltage sensitivity value', FloatRange(), unit='V', default=1, readonly=False) resolution = Parameter('resolution') mode = Parameter('measurement mode: ac/dc', readonly=False) ioClass = HP_IO MODE_NAMES = {0: 'dc', 1: 'ac'} VOLT_RANGE = ['100mV', '1V', '10V', '100V', '1000V'] v_range = Parameter('voltage range', EnumType('voltage index range', {name: idx for idx, name in enumerate(VOLT_RANGE)}), readonly=False) acdc = None def write_mode(self, mode): if mode == 1: self.comm(f'configure:voltage:AC {self.range}, {self.resolution}') else: self.comm(f'configure:voltage:DC {self.range}, {self.resolution}') self.acdc = self.MODE_NAMES[mode] return self.comm(f'function?') def read_value(self): self.comm(f'measure:voltage:') def write_autorange_acdc(self, function): full_function = f'{function}:{self.acdc}' return self.write_autorange(full_function) def read_range_voltage(self): return self.read_range(f'voltage:{self.acdc}') def write_range_voltage(self, range): return self.write_range(f'voltage:{self.acdc}', range) def write_autorange_voltage(self): return self.write_autorange_acdc('voltage') def read_resolution_voltage(self): return self.read_resolution(f'voltage:{self.acdc}') def write_resolution_voltage(self, resolution): return self.write_resolution(f'voltage:{self.acdc}', resolution) class Current(HP34401A, Readable, Voltage): value = Parameter('current', FloatRange, unit='A') range = Parameter('current range', FloatRange) CURR_RANGE_AC = ['10mA', '100mA', '1A', '3A'] CURR_RANGE_DC = ['1A', '3A'] def read_range_current(self): return self.read_range(f'current:{self.acdc}') def write_autrange_current(self): return self.write_autorange_acdc('current') def write_range_current(self, range): return self.write_range(f'current:{self.acdc}', range) def read_resolution_current(self): return self.read_resolution(f'current:{self.acdc}') def write_resolution_current(self, resolution): return self.write_resolution(f'current:{self.acdc}', resolution) class Resistance(HP34401A, Readable): value = Parameter('resistance') mode = Parameter('measurement mode: 2-/4-wire ohms', EnumType(two_wire=2, four_wire=4), readonly=False) resolution = Parameter('resistance measurement resolution') range = Parameter('resistance measurement range') RESIST_RANGE = ['100Om', '1kOm', '10kOm', '100kOm', '1MOm', '10MOm', '100MOm'] FUNCTION_MAP = {2: 'resistance', 4: 'fresistance'} def write_range_resistance(self, range): return self.write_range(f'{self.FUNCTION_MAP[self.mode]}', range) def read_range_resistance(self): return self.read_range(f'{self.FUNCTION_MAP[self.mode]}') def write_mode(self, mode): if mode == 2: self.comm(f'configure:resistance {self.range},{self.resolution}') elif mode == 4: self.comm(f'configure:fresistance {self.range}, {self.resolution}') return self.comm('configure?') def write_autorange_resistance(self): return self.write_autorange(self.FUNCTION_MAP[self.mode]) def read_resolution_resistance(self): return self.read_resolution(f'{self.FUNCTION_MAP[self.mode]}') def write_resolution_resistance(self, resolution): return self.write_resolution(f'{self.FUNCTION_MAP[self.mode]}', resolution) class Frequency(HP34401A, Readable): value = Parameter('frequency', FloatRange(3, 300e3), unit='Hz') def write_autorange_frequency(self): return self.write_autorange('frequency') def read_resolution_frequency(self): return self.read_resolution('frequency') def write_resolution_frequency(self, resolution): return self.write_resolution('frequency', resolution)