Tue, 01 May 2018 00:10:23 +0200
[py3k] beginning to port to py3k
also write a proper setuptools based setup.py and convert some bin/* scripts
as entry_points.
--- a/README Thu Apr 02 16:58:24 2009 +0200 +++ b/README Tue May 01 00:10:23 2018 +0200 @@ -1,4 +1,4 @@ -pygpibtoolkit is (c) 2007-2009 David Douard +pygpibtoolkit is (c) 2007-2018 David Douard and is available under the GNU General Public Licence v2. You can get information on pygpibtoolkit on @@ -6,8 +6,4 @@ See `doc/introduction.rst` for a quick overview. -If you have any questions, please mail david.douard@logilab.fr -for support. - -David Douard - +If you have any questions, please mail david.douard@sdfa3.org for support.
--- a/bin/dump_datablock Thu Apr 02 16:58:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#!/usr/bin/python - -import sys, os -try: - from pygpibtoolkit.HP3562A.dump_datablock import main -except ImportError: - sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) - from pygpibtoolkit.HP3562A.dump_datablock import main -main()
--- a/bin/gpib_detect Thu Apr 02 16:58:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -#!/usr/bin/python -import sys -import os -import signal -import time - -try: - from pygpibtoolkit.gpibcontroller import GPIBController -except ImportError: - sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) - from pygpibtoolkit.gpibcontroller import GPIBController -import pygpibtoolkit.HP3562A -from pygpibtoolkit.prologix import GPIB -def main(): - import optparse - opt = optparse.OptionParser("A simple tool for detecting connected GPIB devices") - opt.add_option('-d', '--device', default="/dev/ttyUSB0", - dest="device", - help="Device of connected Prologix GPIB bundle [/dev/ttyUSB0]",) - options, argv = opt.parse_args(sys.argv) - - print "Detecting GPIB devices on the bus. Please wait until completion." - cnx = GPIB(device=options.device) - c = GPIBController(cnx) - - signal.signal(signal.SIGINT, c.stop) - signal.signal(signal.SIGQUIT, c.stop) - - time.sleep(1) - devices = c.detect_devices() - c.stop() - - print "GPIB devices:" - for k in sorted(devices.keys()): - print "%-3d: %s"%(k, devices[k]) - return c, devices -if __name__ == "__main__": - c, dev = main() -
--- a/bin/read_coord Thu Apr 02 16:58:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#!/usr/bin/python - -import sys, os -try: - from pygpibtoolkit.HP3562A.coord_decoder import main -except ImportError: - sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) - from pygpibtoolkit.HP3562A.coord_decoder import main -main()
--- a/bin/read_state Thu Apr 02 16:58:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#!/usr/bin/python - -import sys, os -try: - from pygpibtoolkit.HP3562A.state_decoder import main -except ImportError: - sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) - from pygpibtoolkit.HP3562A.state_decoder import main -main()
--- a/bin/read_trace Thu Apr 02 16:58:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#!/usr/bin/python -import sys, os -try: - from pygpibtoolkit.HP3562A.trace_decoder import main -except ImportError: - sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) - from pygpibtoolkit.HP3562A.trace_decoder import main -main()
--- a/pygpibtoolkit/HP3456.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3456.py Tue May 01 00:10:23 2018 +0200 @@ -11,14 +11,14 @@ # 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. -""" Copyright (c) 2007-2009 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org """ import mx.DateTime as dt -from pygpibtoolkit.pygpib import Constants, Command -from pygpibtoolkit.pygpib import Mode, ModeCommand +from pygpibtoolkit.pygpib import Command +from pygpibtoolkit.pygpib import ModeCommand from pygpibtoolkit.pygpib import WriteOnlyMode from pygpibtoolkit.pygpib import BoolValue, FloatValue from pygpibtoolkit.gpibcontroller import AbstractGPIBDevice, deviceRegister @@ -27,10 +27,10 @@ class Function(WriteOnlyMode): "Function" _init_value = "S0F1" - - #S0 = ModeCommand("Unshift", "S0") - #S1 = ModeCommand("Shift", "S1") - + + # S0 = ModeCommand("Unshift", "S0") + # S1 = ModeCommand("Shift", "S1") + S0F1 = ModeCommand("DC Voltage", "DCV") S0F2 = ModeCommand("AC Voltage", "ACV") S0F3 = ModeCommand("AC + DC Voltage", "ACV+DCV") @@ -42,12 +42,12 @@ S1F3 = ModeCommand("(AC + DC)/DC Voltage Ratio", "ACV+DCV/DCV") S1F4 = ModeCommand("O.C. 2 wire Ohm", "OCO2") S1F5 = ModeCommand("O.C. 4 wire Ohm", "OCO4") - + class Range(WriteOnlyMode): "Range" _init_value = "R1" - + R1 = ModeCommand("Auto", "AUTO") R2 = ModeCommand("0.1", "0.1") R3 = ModeCommand("1", "1") @@ -58,15 +58,17 @@ R8 = ModeCommand("100E3", "100E3") R9 = ModeCommand("1E6", "1E6") + class Trigger(WriteOnlyMode): "Trigger" _init_value = "T1" - + T1 = ModeCommand("Internat", "INT") T2 = ModeCommand("External", "EXT") T3 = ModeCommand("Single", "SGL") T4 = ModeCommand("Hold", "HLD") + class Math(WriteOnlyMode): "Math" _init_value = "M0" @@ -81,7 +83,8 @@ M7 = ModeCommand("Scale", "") M8 = ModeCommand("% Error", "") M9 = ModeCommand("dB", "") - + + class AutoZero(WriteOnlyMode): "Auto Zero" _init_value = "Z1" @@ -89,6 +92,7 @@ Z0 = ModeCommand("Off", "OFF") Z1 = ModeCommand("On", "ON") + class Filter(WriteOnlyMode): "Filter" _init_value = "FL0" @@ -96,6 +100,7 @@ FL0 = ModeCommand("Off", "OFF") FL1 = ModeCommand("On", "ON") + class Test(WriteOnlyMode): "Test" _init_value = "TE0" @@ -103,13 +108,15 @@ TE0 = ModeCommand("Off", "OFF") TE1 = ModeCommand("On", "ON") + class ReadingStorage(WriteOnlyMode): "Reading Storage" _init_value = "RS0" RS0 = ModeCommand("Off", "OFF") RS1 = ModeCommand("On", "ON") - + + class SystemOutputMode(WriteOnlyMode): "System Output Mode" _init_value = "SO0" @@ -117,6 +124,7 @@ SO0 = ModeCommand("Off", "OFF") SO1 = ModeCommand("On", "ON") + class Display(WriteOnlyMode): "Display" _init_value = "D1" @@ -124,6 +132,7 @@ D0 = ModeCommand("Off", "OFF") D1 = ModeCommand("On", "ON") + class OutputFormat(WriteOnlyMode): "Output Format" _init_value = "P0" @@ -131,81 +140,99 @@ P0 = ModeCommand("ASCII", "ASC") P1 = ModeCommand("Packed Format", "PFOR") + class EOI(WriteOnlyMode): "EOI" _init_value = "O1" - + O0 = ModeCommand("Disable", "OFF") O1 = ModeCommand("Enable", "ON") + class SW1(BoolValue): _readonly = True + def convert_from(self, *value): if value: - return int(value[0]) and "Front" or "Rear" + return int(value[0]) and "Front" or "Rear" return "?" + class H(Command): "HOME - Software Reset" + class CL1(Command): "CLEAR CONTINUE - Active" + class _Register(FloatValue): _readonly = False _cached = False + def build_get_cmd(self): - return "RE"+self.__class__.__name__ + return "RE" + self.__class__.__name__ def build_set_cmd(self, *value): value = self.convert_to(*value) - cmd = "%sST%s"%(value, self.__class__.__name__) + cmd = "%sST%s" % (value, self.__class__.__name__) return cmd, value + class N(_Register): "Number of readings" + class G(_Register): "Number of displayed digits" + class I(_Register): "Number of power line cycles int." + class D(_Register): "Delay" + class M(_Register): "Mean" _readonly = True - + + class V(_Register): "Variance" _readonly = True + class C(_Register): "Count" _readonly = True - + + class L(_Register): "Lower" - + + class R(_Register): "R" + class U(_Register): "Upper" - + + class Y(_Register): "Y" - + + class Z(_Register): "Z" - - + class HP3456Device(AbstractGPIBDevice): - _accepts = [r"^(?P<model>HP3456A)$",] - _idn = None # cannot ask device its model number or version + _accepts = [r"^(?P<model>HP3456A)$", ] + _idn = None # cannot ask device its model number or version def __init__(self, idn, address, controller): super(HP3456Device, self).__init__(idn, address, controller) @@ -213,7 +240,7 @@ self._data_cb = None def manage_srq(self, statusbyte): - #print "Managing SRQ", statusbyte + # print "Managing SRQ", statusbyte if statusbyte & 0x04: # data ready, read the value on the GPIB bus self._controller.send_command(self._address, '', cb=self.data_cb) @@ -234,5 +261,5 @@ def register_data_cb(self, cb): self._data_cb = cb - + deviceRegister.register_manager(HP3456Device)
--- a/pygpibtoolkit/HP3562A/HP356X.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/HP356X.py Tue May 01 00:10:23 2018 +0200 @@ -10,14 +10,14 @@ # 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. -""" Copyright (c) 2007-2009 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org """ from pygpibtoolkit.pygpib import Constants, Command from pygpibtoolkit.pygpib import Condition -from pygpibtoolkit.pygpib import BoolValue, IntValue, FloatValue +from pygpibtoolkit.pygpib import BoolValue, IntValue from pygpibtoolkit.pygpib import PercentageValue, FrequencyValue, DurationValue from pygpibtoolkit.pygpib import VoltageValue from pygpibtoolkit.pygpib import EnumValue, StringValue @@ -25,6 +25,7 @@ from pygpibtoolkit.gpibcontroller import AbstractGPIBDevice, deviceRegister + ##################### # HP3562A constants and command set # **VERY INCOMPLETE** @@ -32,20 +33,22 @@ class LinRes(Condition): def __call__(self, device): return device.MeasMode == "LINEAR RES" -class LogRes(Condition): +class LogRes(Condition): # noqa def __call__(self, device): return device.MeasMode == "LOG RES" -class SweptSine(Condition): +class SweptSine(Condition): # noqa def __call__(self, device): return device.MeasMode == "SWEPT SINE" -class TimeCaptur(Condition): +class TimeCaptur(Condition): # noqa def __call__(self, device): return device.MeasMode == "TIME CAPTUR" + # GPIB buffer size is 3x80 characters lines class STATUS_BYTE(Constants): # HP3562A Status Byte, as returned by a serial poll - _constants = [(0x40, "RQS", "Request Service"), # when sent in response to a serial poll + _constants = [(0x40, "RQS", "Request Service"), + # when sent in response to a serial poll (0x20, "ERR", "GPIB error"), (0x10, "RDY", "ready to accept GPIB commands"), ] @@ -61,23 +64,25 @@ (8, "USRQ1", "User SRQ #8"), (9, "EOD", "End of disk action"), (10, "EOP", "End of plot action"), - (11, "STCH", "Instrument status changed"), # any change in - # the status register sets this condition + (11, "STCH", "Instrument status changed"), + # STCH: any change in the status register sets this condition (12, "PWR", "Power on"), (13, "KEY", "Key pressed"), (14, "DCP", "Device clear plotter (listen)"), # ... ] + def __init__(self): super(STATUS_BYTE, self).__init__() self._conditions = dict([(x[0], x[1]) for x in self.conditions]) self._rev_conditions = dict([(x[1], x[0]) for x in self.conditions]) self._long_conditions = dict([(x[0], x[2]) for x in self.conditions]) - + def byte_condition(self, byte): byte = byte & 0x8F return self._conditions.get(byte, "N/A") + class IS(Flag): "INTERNAL STATUS - Internal Status Register" _constants = [(0x01, "MEASP", "measeurement pause"), @@ -96,7 +101,8 @@ (0x2000, "ASRC", "Asctive Status Register changed"), (0x4000, "PWRF", "Power-on test failed"), ] - + + class STA(Flag): "STATUS QUERY - Status/event query" _constants = [(0x01, "N/A", "Not used"), @@ -116,6 +122,8 @@ (0x4000, "CH2OV", "Channel 2 overrange"), (0x8000, "MAOV", "Math overflow"), ] + + class AS(Flag): "ACTIVITY STATUS - Activity Status Register" _constants = [(0x01, "CKFL", "Check fault log"), @@ -125,7 +133,7 @@ (0x10, "MSSM", "Missed sample"), (0x20, "TMPR", "Timed preview"), (0x40, "ACDA", "Accept data"), - #... + # ... ] @@ -137,40 +145,49 @@ def get_mode(self, device): # XXX Can I get this from the device? - #mode = device.DSBN. # HERE + # mode = device.DSBN. # HERE return None - + + class ARM(Command): "ARM - Arm" + + class NAVG(IntValue): "Number of averages" + class AverageMode(Mode): "Average mode" _condition = LinRes() | LogRes() | TimeCaptur() _key = "EAVGTYP" _DATA_BLOCK = "DSBN" - + STBL = ModeCommand(6, "STABLE (MEAN)") - EXP = ModeCommand(7, "EXPON") + EXP = ModeCommand(7, "EXPON") PHLD = ModeCommand(8, "PEAK HOLD") CNPK = ModeCommand(9, "CONT PEAK") AVOF = ModeCommand(10, "AVG OFF") + class TIAV(BoolValue): "TIM AV ON OFF - Time average" _condition = LinRes() | TimeCaptur() | SweptSine() + class OVLP(PercentageValue): "OVRLP% - Overlap (%)" _condition = LinRes() | TimeCaptur() | SweptSine() - + + class AUTO(BoolValue): "AUTO ON OFF - Auto calibration" + class SNGC(Command): "SINGLE CAL - Single calibration" + class CoordMode(Mode): "Coord mode" _key = "EYCOORD" @@ -179,60 +196,73 @@ MGDB = ModeCommand(5, "MAG (dB)") MDBM = ModeCommand(10, "MAG (dBm)") MGLG = ModeCommand(4, "MAG (LOG)") - MAG = ModeCommand(3, "MAG (LIN)") + MAG = ModeCommand(3, "MAG (LIN)") PHSE = ModeCommand(8, "PHASE") REAL = ModeCommand(1, "REAL") IMAG = ModeCommand(2, "IMAG") NYQT = ModeCommand(6, "NYQUIST") NICL = ModeCommand(9, "NICHOL") + # FREQ menu class FRS(FrequencyValue): "FREQ SPAN - Freq. span" + class SF(FrequencyValue): "START FREQ - Start freq." + class CF(FrequencyValue): "CENTER FREQ - Center freq." - _units = "hz","khz","mhz","ord","rmp" + _units = "hz", "khz", "mhz", "ord", "rmp" _condition = LinRes() | TimeCaptur() | SweptSine() - + + class ZST(Command): "ZERO START - Zero start" _condition = LinRes() | TimeCaptur() | SweptSine() - + + class MAXS(FrequencyValue): "MAX SPAN - Max span" _condition = LinRes() | TimeCaptur() | SweptSine() - + + class TLN(DurationValue): "TIME LENGTH - Time len." _condition = LinRes() | TimeCaptur() | SweptSine() - + + class ESMP(BoolValue): "E SMPL ON OFF - E sample" _condition = LinRes() | TimeCaptur() | SweptSine() - + + class SMPF(FrequencyValue): "SAMPLE FREQ - Sample freq." _condition = LinRes() | TimeCaptur() | SweptSine() - + + class SPF(FrequencyValue): "STOP FREQ - Stop freq." _condition = SweptSine - + + class SWRT(FrequencyValue): "SWEEP RATE - Sweep rate" + class ABIB(Command): "ABORT HP-IB - Abort HPIB" + # INPUT COUPLING class C1AC(EnumValue): "CHAN1 AC DC - Channel 1 AC/DC" _values = ["DC", "AC"] - + + class Chan1Coupling(Mode): "Channel 1 coupling" _key = "FLT1" @@ -240,10 +270,12 @@ FLT1 = ModeCommand(1, "FLOAT CHAN1") GND1 = ModeCommand(0, "GROUND CHAN1") + class C2AC(EnumValue): "CHAN2 AC DC - Channel 2 AC/DC" _values = ["AC", "DC"] - + + class Chan2Coupling(Mode): "Channel 2 coupling" _key = "FLT1" @@ -251,16 +283,20 @@ FLT2 = ModeCommand("Float", "FLOAT CHAN2") GND2 = ModeCommand("Ground", "GROUND CHAN2") + class LCL(Command): "LOCAL - Local" + class C1RG(VoltageValue): "CHAN 1 RANGE - Channel 1 range" - _units = "V","mV","Vrms","mVrms","dBV", "EU" + _units = "V", "mV", "Vrms", "mVrms", "dBV", "EU" + class C2RG(VoltageValue): "CHAN 2 RANGE - Channel 2 range" - _units = "V","mV","Vrms","mVrms","dBV", "EU" + _units = "V", "mV", "Vrms", "mVrms", "dBV", "EU" + # MEAS MODE class MeasMode(Mode): @@ -271,20 +307,38 @@ LGRS = ModeCommand(1, "LOG RES") SSIN = ModeCommand(2, "SWEPT SINE") CPTR = ModeCommand(3, "TIME CAPTUR") - + + # MEAS DISP class FreqResp(Condition): def __call__(self, device): return device.SelectMeas == "FREQ RESP" + class MeasDisp(Mode): # TODO - FRQR = ModeCommand(0, "FREQ RESP", condition=(LinRes() | LogRes()) & FreqResp() | SweptSine()) - COHR = ModeCommand(0, "COHER", condition=(LinRes() | LogRes()) & FreqResp() | SweptSine()) - PSP1 = ModeCommand(0, "POWER SPEC1", condition=(LinRes() | LogRes()) & FreqResp() | SweptSine()) - PSP2 = ModeCommand(0, "POWER SPEC2", condition=(LinRes() | LogRes()) & FreqResp() | SweptSine()) - CSPS = ModeCommand(0, "CROSS SPEC", condition=(LinRes() | LogRes()) & FreqResp() | SweptSine()) - IRSP = ModeCommand(0, "IMPLS RESP", condition=LinRes() & FreqResp()) + FRQR = ModeCommand(0, "FREQ RESP", + condition=((LinRes() | LogRes()) + & FreqResp() + | SweptSine())) + COHR = ModeCommand(0, "COHER", + condition=((LinRes() | LogRes()) + & FreqResp() + | SweptSine())) + PSP1 = ModeCommand(0, "POWER SPEC1", + condition=((LinRes() | LogRes()) + & FreqResp() + | SweptSine())) + PSP2 = ModeCommand(0, "POWER SPEC2", + condition=((LinRes() | LogRes()) + & FreqResp() + | SweptSine())) + CSPS = ModeCommand(0, "CROSS SPEC", + condition=((LinRes() | LogRes()) + & FreqResp() + | SweptSine())) + IRSP = ModeCommand(0, "IMPLS RESP", + condition=LinRes() & FreqResp()) AUMT = ModeCommand(0, "AUTO MATH", ) FILT = ModeCommand(0, "FILTRD INPUT") @@ -292,26 +346,28 @@ TMR2 = ModeCommand(0, "TIME REC2", condition=TimeCaptur) LSP1 = ModeCommand(0, "LINEAR SPEC1", condition=TimeCaptur) LSP2 = ModeCommand(0, "LINEAR SPEC2", condition=TimeCaptur) - + class PowerSpec(Condition): def __call__(self, device): return device.SelectMeas == "POWER SPEC" + class AutoCorr(Condition): def __call__(self, device): return device.SelectMeas == "AUTO CORR" + class CrossCorr(Condition): def __call__(self, device): return device.SelectMeas == "CROSS CORR" + class Hist(Condition): def __call__(self, device): return device.SelectMeas == "HIST" - # SELECT MEAS class SelectMeas(Mode): "Select measurement" @@ -319,16 +375,22 @@ _DATA_BLOCK = "DSBN" _condition = LinRes() | TimeCaptur() | SweptSine() - FRSP = ModeCommand(0, "FREQ RESP", condition=LinRes() | LogRes() | SweptSine()) - PSPC = ModeCommand(2, "POWER SPEC", condition=LinRes() | LogRes() | TimeCaptur()) - AUCR = ModeCommand(3, "AUTO CORR", condition=LinRes() | TimeCaptur()) - CCOR = ModeCommand(1, "CROSS CORR", condition=LinRes()) - HIST = ModeCommand(4, "HIST", condition=LinRes() | TimeCaptur()) + FRSP = ModeCommand( + 0, "FREQ RESP", condition=LinRes() | LogRes() | SweptSine()) + PSPC = ModeCommand( + 2, "POWER SPEC", condition=LinRes() | LogRes() | TimeCaptur()) + AUCR = ModeCommand( + 3, "AUTO CORR", condition=LinRes() | TimeCaptur()) + CCOR = ModeCommand( + 1, "CROSS CORR", condition=LinRes()) + HIST = ModeCommand( + 4, "HIST", condition=LinRes() | TimeCaptur()) + class Channel(Mode): "" _key = "ECH" - _DATA_BLOCK = "DDBN" # XXX sure? + _DATA_BLOCK = "DDBN" # XXX sure? CH12 = ModeCommand("Channel 1&2 active", "CH 1&2 ACTIVE", condition=LinRes() | LogRes()) CH1 = ModeCommand("Channel 1 active", "CH 1 ACTIVE", @@ -336,17 +398,22 @@ CH2 = ModeCommand("Channel 2 active", "CH 2 ACTIVE", condition=LinRes() | LogRes() | TimeCaptur()) + class REV(StringValue): _readonly = True "REVISION - Revision" + class SACR(Command): "SACR - Send Auto Carrier" - + + class HP356XDevice(AbstractGPIBDevice): - _accepts = [ r"^(?P<model>HP *356[23][ABCD]).*$",] + _accepts = [r"^(?P<model>HP *356[23][ABCD]).*$", ] _idn = "ID?" + def manage_srq(self, statusbyte): - print "Managing SRQ", statusbyte - + print("Managing SRQ: %s" % statusbyte) + + deviceRegister.register_manager(HP356XDevice)
--- a/pygpibtoolkit/HP3562A/__init__.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/__init__.py Tue May 01 00:10:23 2018 +0200 @@ -10,15 +10,15 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org HP356X ====== -Module for communicating with the HP 3562A and derivated Digital -Signal Analyzers. +Module for communicating with the HP 3562A and derivated Digital Signal +Analyzers. Subpackages ----------- @@ -28,7 +28,4 @@ --------- """ -import HP356X - - - +from . import HP356X # noqa
--- a/pygpibtoolkit/HP3562A/coord_decoder.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/coord_decoder.py Tue May 01 00:10:23 2018 +0200 @@ -11,8 +11,8 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org state_decoder ============= @@ -20,22 +20,25 @@ Module for decoding the internal state of the HP3562A DSA, using the GPIB command "DSBN" (Dump State BiNary). -This file can be exectued as a python script. Use '-h' for more informations. +This file can be exectued as a python script. Use '-h' for more informations. + """ -from pygpibtoolkit.gpib_utils import format_datablock_header, decode_datablock_header, read_datablock_trace -from pygpibtoolkit.gpib_utils import decode_float, decode_string -from pygpibtoolkit.HP3562A.trace_decoder import decode_trace, HEADER as TRACE_HEADER -from pygpibtoolkit.HP3562A.enum_types import * +from pygpibtoolkit.gpib_utils import ( + decode_datablock_header, read_datablock_trace, + decode_float, ) +from pygpibtoolkit.HP3562A.trace_decoder import HEADER as TRACE_HEADER +from pygpibtoolkit.HP3562A.enum_types import * # noqa + HEADER = [("EYCOORD", "Y coordinates", EYCOORD, 'h', 2), - ("", "# of disp elements", int, "h", 2), - ("", "First element", int, "h", 2), + ("", "# of disp elements", int, 'h', 2), + ("", "First element", int, 'h', 2), ("", "Total elements", int, 'h', 2), ("", "Display sampling", EDISPSMP, 'h', 2), ("", "Scaling", ESCAL, 'h', 2), - ("", "Data pointer", long, 'l', 4), - ("", "In data", long, 'l', 4), + ("", "Data pointer", int, 'l', 4), + ("", "In data", int, 'l', 4), ("", "Log/linear x-axis", bool, 'h', 2), ("", "Sampled display data", bool, 'h', 2), ("", "Plot/Graph mode", bool, 'h', 2), @@ -55,8 +58,9 @@ ("", "Left grid", decode_float, None, 8), ("", "Right grid", decode_float, None, 8), ("", "Left data", decode_float, None, 8), - ("", "Right data", decode_float, None, 8), - ] + ("", "Right data", decode_float, None, 8), + ] + def decode_coord(data): """ @@ -69,73 +73,75 @@ trace_header, idx = decode_datablock_header(data, TRACE_HEADER, idx) trace = read_datablock_trace(data, idx, trace_header["Number of elements"]) return header, trace_header, trace - + def main(): import sys - import optparse + import argparse import numpy - - opt = optparse.OptionParser("A simple tool for displaying dumped coord data block") - opt.add_option('-f', '--filename', default=None, - dest='filename', - help='Output filename. If not set, read from stdin') - opt.add_option('-m', '--mode', default='binary', - dest='mode', - help='Dumping mode (may be "binary" [default], "ascii" or "ansi")', - ) - opt.add_option('-d', '--display-header', default=False, - action="store_true", - dest="displayheader", - help="Display the trace header") - opt.add_option('-P', '--noplot-trace', default=True, - action="store_false", - dest="plot", - help="Do not display the plot of the trace") - opt.add_option('-x', '--xmode', default='lin', - dest='xmode', - help='X coordinate mode (may be "lin" [default] or "log")') - opt.add_option('-y', '--ymode', default='lin', - dest='ymode', - help='Y coordinate mode (may be "lin" [default], "log" or "db")') - - options, argv = opt.parse_args(sys.argv) + opt = argparse.ArgumentParser( + "A simple tool for displaying dumped coord data block") + opt.add_argument( + '-f', '--filename', default=None, dest='filename', + help='Input filename. If not set, read from stdin') + opt.add_argument( + '-m', '--mode', default='binary', dest='mode', + help='Dumping mode (may be "binary" [default], "ascii" or "ansi")') + opt.add_argument( + '-d', '--display-header', default=False, action="store_true", + dest="displayheader", help="Display the trace header") + opt.add_argument( + '-P', '--noplot-trace', default=True, action="store_false", + dest="plot", help="Do not display the plot of the trace") + opt.add_argument( + '-x', '--xmode', default='lin', dest='xmode', + help='X coordinate mode (may be "lin" [default] or "log")') + opt.add_argument( + '-y', '--ymode', default='lin', dest='ymode', + help='Y coordinate mode (may be "lin" [default], "log" or "db")') + + options = opt.parse_args() if options.filename is None: - print "Can't deal stdin for now..." + print("Can't deal stdin for now...") sys.exit(1) try: - coord_header, header, data = decode_coord(open(options.filename, 'rb').read()) - except Exception, e: - print "ERROR: can't read %s an interpret it as a HP3562 trace"%options.filename - print e + with open(options.filename, 'rb') as f: + coord_header, header, data = decode_coord(f.read()) + except Exception as e: + print("ERROR: can't read %s or interpret it as a HP3562 trace" + % options.filename) + print(e) + raise sys.exit(1) if options.displayheader: - print format_header(coord_header, HEADER, 100) - print format_header(header, TRACE_HEADER, 100) + print(format_header(coord_header, HEADER, 100)) + print(format_header(header, TRACE_HEADER, 100)) if options.plot: f0 = header['Start freq value'] dx = header['Delta X-axis'] n = header['Number of elements'] - x = numpy.linspace(f0, f0+dx*n, len(data)) + x = numpy.linspace(f0, f0+dx*n, len(data)) y = data.copy() ym = coord_header['Min value of data'] yM = coord_header['Max value of data'] ys = coord_header['Y scale factor'] - - y[y<ym] = ym + + y[y < ym] = ym y *= ys - + import pylab pylab.ylabel(header['Amplitude units']) pylab.grid() pylab.plot(x, y) - pylab.xlabel('frequency (%s)'%header["X axis units"]) - pylab.ylabel("%s (%s)"%(coord_header['Y coordinates'], header['Amplitude units']) ) + pylab.xlabel('frequency (%s)' % header["X axis units"]) + pylab.ylabel("%s (%s)" % ( + coord_header['Y coordinates'], header['Amplitude units'])) pylab.show() - + + if __name__ == "__main__": main()
--- a/pygpibtoolkit/HP3562A/dump_datablock.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/dump_datablock.py Tue May 01 00:10:23 2018 +0200 @@ -10,13 +10,14 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org + """ import sys import time -import pygpibtoolkit.pygpib +import pygpibtoolkit.pygpib # noqa from pygpibtoolkit import prologix @@ -25,20 +26,23 @@ Class dedicated to dump data blocks from HP3562A DSA (trace, internal state or coordinate). """ - MODES = {'trace': 'DD', - 'state': 'DS', - 'coord': 'DC', - } - - FORMATS = {'binary': 'BN', - 'ascii': 'AS', - 'ansi': 'AN'} - + MODES = { + 'trace': 'DD', + 'state': 'DS', + 'coord': 'DC', + } + + FORMATS = { + 'binary': 'BN', + 'ascii': 'AS', + 'ansi': 'AN', + } + def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1, address=0): - super(HP3562dumper, self).__init__(device, baudrate, timeout, address, mode=1) + super().__init__(device, baudrate, timeout, address, mode=1) - def dump(self, mode='trace', format="binary"): + def dump(self, mode='trace', format="binary"): """ Dump the required data block and return it as a raw string buffer. @@ -52,53 +56,52 @@ cmd = self.MODES[mode] + self.FORMATS[format] res = "" - print "command = ", cmd + print("command = %s" % cmd) # warning, this use direct low level serial communications... - self._cnx.write('%s\r'%cmd) + self._cnx.write('%s\r' % cmd) i = 0 - while i<self._retries: + while i < self._retries: l = self._cnx.readline() if l.strip() == "": i += 1 time.sleep(self._timeout) continue - res += l + res += l i = 0 return res - def main(): - import optparse - opt = optparse.OptionParser("A simple tool for dumping the current trace") - opt.add_option('-f', '--filename', default=None, - dest='filename', - help='Output filename. If not set, write to stdout') - opt.add_option('-d', '--device', default='/dev/ttyUSB0', - dest='device', - help='Device of the RS232 connection (default: /dev/ttyUSB0)', - ) - opt.add_option('-a', '--address', default=0, - dest='address', - help='GPIB address of the device', - ) - opt.add_option('-b', '--block', default='trace', - dest='block', - help='Data block to dump (may be "trace" [default], "state" or "coord")', - ) - opt.add_option('-m', '--mode', default='binary', - dest='mode', - help='Dumping mode (may be "binary" [default], "ascii" or "ansi")', - ) - options, argv = opt.parse_args(sys.argv) + import argparse + opt = argparse.ArgumentParser( + "A simple tool for dumping the current trace") + opt.add_argument( + '-f', '--filename', default=None, dest='filename', + help='Output filename. If not set, write to stdout') + opt.add_argument( + '-d', '--device', default='/dev/ttyUSB0', dest='device', + help='Device of the RS232 connection (default: /dev/ttyUSB0)') + opt.add_argument( + '-a', '--address', default=0, dest='address', + help='GPIB address of the device') + opt.add_argument( + '-b', '--block', default='trace', dest='block', + help=('Data block to dump (may be "trace" [default], ' + '"state" or "coord")')) + opt.add_argument( + '-m', '--mode', default='binary', dest='mode', + help='Dumping mode (may be "binary" [default], "ascii" or "ansi")') + + options = opt.parse_args() cnx = HP3562dumper(device=options.device, address=int(options.address)) res = cnx.dump(mode=options.block, format=options.mode) - sys.stderr.write("read %s bytes\n"%(len(res))) + sys.stderr.write("read %s bytes\n" % (len(res))) if options.filename: open(options.filename, 'w').write(res) else: - print res - -if __name__=='__main__': + print(res) + + +if __name__ == '__main__': main()
--- a/pygpibtoolkit/HP3562A/dump_datablock_mockup.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/dump_datablock_mockup.py Tue May 01 00:10:23 2018 +0200 @@ -10,18 +10,20 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org + """ import glob -import os import time import random + class HP3562dumper: - """ - A mockup thet will find in a directory some HPGL files and feed them randomly + """A mockup that will find in a directory some HPGL files and feed them + randomly + """ def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1, address=5): @@ -33,12 +35,12 @@ def dump(self, mode='trace', format="binary"): fn = random.choice(self.filenames[mode]) - ret = open(fn, 'rb').read() - if len(ret)>0: - time.sleep(random.randint(1,3)) + with open(fn, 'rb') as f: + ret = f.read() + if len(ret) > 0: + time.sleep(random.randint(1, 3)) return ret return None def send_command(self, *args): pass -
--- a/pygpibtoolkit/HP3562A/enum_types.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/enum_types.py Tue May 01 00:10:23 2018 +0200 @@ -11,233 +11,258 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org Constants used for HP3562A data block interpretation. + """ -EDSP = {0: "No data", - 1: "Frequency response", - 2: "Power spectrum 1", - 3: "Power spectrum 2", - 4: "Coherence", - 5: "Cross spectrum", - 6: "Input time 1", - 7: "Input time 2", - 8: "Input linear spectrum 1", - 9: "Input linear spectrum 2", - 10: "Impulse response", - 11: "Cross correlation", - 12: "Auto correlation 1", - 13: "Auto correlation 2", - 14: "Histogram 1", - 15: "Histogram 2", - 16: "Cumulative density function 1", - 17: "Cumulative density function 2", - 18: "Probability density function 1", - 19: "Probability density function 2", - 20: "Average linear spectrum 1", - 21: "Average linear spectrum 2", - 22: "Average time record 1", - 23: "Average time record 2", - 24: "Synthesis pole-zeros", - 25: "Synthesis pole-residue", - 26: "Synthesis polynomial", - 27: "Synthesis constant", - 28: "Windowed time record 1", - 29: "Windowed time record 2", - 30: "Windowed linear spectrum 1", - 31: "Windowed linear spectrum 2", - 32: "Filtered time record 1", - 33: "Filtered time record 2", - 34: "Filtered linear spectrum 1", - 35: "Filtered linear spectrum 2", - 36: "Time capture buffer", - 37: "Captured linear spectrum", - 38: "Captured time record", - 39: "Throughput time record 1", - 40: "Throughput time record 2", - 41: "Curve fit", - 42: "Weighted function", - 43: "Not used", - 44: "Orbits", - 45: "Demodulation polar", - 46: "Preview demod record 1", - 47: "Preview demod record 2", - 48: "Preview demod linear spectrum 1", - 49: "Preview demod linear spectrum 2", - } +EDSP = { + 0: "No data", + 1: "Frequency response", + 2: "Power spectrum 1", + 3: "Power spectrum 2", + 4: "Coherence", + 5: "Cross spectrum", + 6: "Input time 1", + 7: "Input time 2", + 8: "Input linear spectrum 1", + 9: "Input linear spectrum 2", + 10: "Impulse response", + 11: "Cross correlation", + 12: "Auto correlation 1", + 13: "Auto correlation 2", + 14: "Histogram 1", + 15: "Histogram 2", + 16: "Cumulative density function 1", + 17: "Cumulative density function 2", + 18: "Probability density function 1", + 19: "Probability density function 2", + 20: "Average linear spectrum 1", + 21: "Average linear spectrum 2", + 22: "Average time record 1", + 23: "Average time record 2", + 24: "Synthesis pole-zeros", + 25: "Synthesis pole-residue", + 26: "Synthesis polynomial", + 27: "Synthesis constant", + 28: "Windowed time record 1", + 29: "Windowed time record 2", + 30: "Windowed linear spectrum 1", + 31: "Windowed linear spectrum 2", + 32: "Filtered time record 1", + 33: "Filtered time record 2", + 34: "Filtered linear spectrum 1", + 35: "Filtered linear spectrum 2", + 36: "Time capture buffer", + 37: "Captured linear spectrum", + 38: "Captured time record", + 39: "Throughput time record 1", + 40: "Throughput time record 2", + 41: "Curve fit", + 42: "Weighted function", + 43: "Not used", + 44: "Orbits", + 45: "Demodulation polar", + 46: "Preview demod record 1", + 47: "Preview demod record 2", + 48: "Preview demod linear spectrum 1", + 49: "Preview demod linear spectrum 2", +} -ECH = {0: "Channel 1", - 1: "Channel 2", - 2: "Channel 1&2", - 3: "No channel", - } +ECH = { + 0: "Channel 1", + 1: "Channel 2", + 2: "Channel 1&2", + 3: "No channel", +} EOVR = ECH -EDOM = {0: 'Time', - 1: 'Frequency', - 2: 'Voltage (amplitude)', - } +EDOM = { + 0: 'Time', + 1: 'Frequency', + 2: 'Voltage (amplitude)', +} -EVLT = {0: "Peak", - 1: "RMS", - 2: "Volt (indicates peak only)", - } +EVLT = { + 0: "Peak", + 1: "RMS", + 2: "Volt (indicates peak only)", +} + +EAMP = { + 0: "Volts", + 1: "Volts²", + 2: "PSD (V²/Hz)", + 3: "ESD (V²s/Hz)", + 4: "PSD¹² (V/Hz¹²)", + 5: "No unit", + 6: "Unit volts", + 7: "Unit volts²", +} -EAMP = {0: u"Volts", - 1: u"Volts²", - 2: u"PSD (V²/Hz)", - 3: u"ESD (V²s/Hz)", - 4: u"PSD¹² (V/Hz¹²)", - 5: u"No unit", - 6: u"Unit volts", - 7: u"Unit volts²", - } - -EXAXIS= {0: u"No units", - 1: u"Hertz", - 2: u"RPM", - 3: u"Orders", - 4: u"Seconds", - 5: u"Revs", - 6: u"Degrees", - 7: u"dB", - 8: u"dBV", - 9: u"Volts", - 10: u"V\u221AHz", - 11: u"Hz/s", - 12: u"V/EU", - 13: u"Vrms", - 14: u"V²/Hz", - 15: u"%", - 16: u"Points", - 17: u"Records", - 18: u"Ohms", - 19: u"Hertz/octave", - 20: u"Pulse/Rev", - 21: u"Decades", - 22: u"Minutes", - 23: u"V²s/Hz", - 24: u"Octave", - 25: u"Seconds/Decade", - 26: u"Seconds/Octave", - 27: u"Hz/Point", - 28: u"Points/Sweep", - 29: u"Points/Decade", - 30: u"Points/Octave", - 31: u"V/Vrms", - 32: u"V²", - 33: u"EU referenced to chan 1", - 34: u"EU referenced to chan 2", - 35: u"EU value", - } +EXAXIS= { + 0: "No units", + 1: "Hertz", + 2: "RPM", + 3: "Orders", + 4: "Seconds", + 5: "Revs", + 6: "Degrees", + 7: "dB", + 8: "dBV", + 9: "Volts", + 10: "V\u221AHz", + 11: "Hz/s", + 12: "V/EU", + 13: "Vrms", + 14: "V²/Hz", + 15: "%", + 16: "Points", + 17: "Records", + 18: "Ohms", + 19: "Hertz/octave", + 20: "Pulse/Rev", + 21: "Decades", + 22: "Minutes", + 23: "V²s/Hz", + 24: "Octave", + 25: "Seconds/Decade", + 26: "Seconds/Octave", + 27: "Hz/Point", + 28: "Points/Sweep", + 29: "Points/Decade", + 30: "Points/Octave", + 31: "V/Vrms", + 32: "V²", + 33: "EU referenced to chan 1", + 34: "EU referenced to chan 2", + 35: "EU value", +} -EMEAS = {0: "Linear resolution", - 1: "Log resolution", - 2: "Swept sine", - 3: "Time capture", - 4: "Linear resolution throughput", - } +EMEAS = { + 0: "Linear resolution", + 1: "Log resolution", + 2: "Swept sine", + 3: "Time capture", + 4: "Linear resolution throughput", +} -EDEMOD = {45: "AM", - 46: "FM", - 47: "PM", - } +EDEMOD = { + 45: "AM", + 46: "FM", + 47: "PM", +} -EAVG = {0: "No data", - 1: "Not averaged", - 2: "Averaged",} +EAVG = { + 0: "No data", + 1: "Not averaged", + 2: "Averaged", +} -EWIN = {0: "N/A", - 1: "Hann", - 2: "Flat top", - 3: "Uniforme", - 4: "Exponential", - 5: "Force", - 6: "Force chan 1/expon chan 2", - 7: "Expon chan 1/force chan 2", - 8: "User", - } +EWIN = { + 0: "N/A", + 1: "Hann", + 2: "Flat top", + 3: "Uniforme", + 4: "Exponential", + 5: "Force", + 6: "Force chan 1/expon chan 2", + 7: "Expon chan 1/force chan 2", + 8: "User", +} -EMTYP = {0: "Frequency responce", - 1: "Cross correlation", - 2: "Power spectrum", - 3: "Auto correlation", - 4: "Histogram", - 5: "No measurement", - } +EMTYP = { + 0: "Frequency responce", + 1: "Cross correlation", + 2: "Power spectrum", + 3: "Auto correlation", + 4: "Histogram", + 5: "No measurement", +} -EWINTYP = { 11: "Hanning", - 12: "Flat top", - 13: "Uniform", - 14: "User window", - 15: "Force/Exponential", - } +EWINTYP = { + 11: "Hanning", + 12: "Flat top", + 13: "Uniform", + 14: "User window", + 15: "Force/Exponential", +} -EFEXPW = { 0: "Force", - 1: "Exponential", - } +EFEXPW = { + 0: "Force", + 1: "Exponential", +} -EAVGTYP = { 6: "Stable", - 7: "Exponential", - 8: "Peak", - 9: "Continuous peak", - 10: "Averaging off", - } +EAVGTYP = { + 6: "Stable", + 7: "Exponential", + 8: "Peak", + 9: "Continuous peak", + 10: "Averaging off", +} -ETRGTYP = { 18: "Free run", - 19: "Channel 1", - 20: "Channel 2", - 21: "External", - 22: "Source trigger", - 23: "HP-IB trigger", - } +ETRGTYP = { + 18: "Free run", + 19: "Channel 1", + 20: "Channel 2", + 21: "External", + 22: "Source trigger", + 23: "HP-IB trigger", +} -ETRGSLP = { 16: "Positive", - 17: "Negative", - } +ETRGSLP = { + 16: "Positive", + 17: "Negative", +} -EPRVTYP = { 0: "Manual preview", - 1: "Timed preview", - 2: "Preview off", - } +EPRVTYP = { + 0: "Manual preview", + 1: "Timed preview", + 2: "Preview off", +} -ESMPTYP = { 24: "Internal sample", - 25: "External sample", - } +ESMPTYP = { + 24: "Internal sample", + 25: "External sample", +} ERNGUNT = EXAXIS -ERNGTYP = { 26: "Auto range on", - 27: "Auto range off", - 28: "Auto range set", - } +ERNGTYP = { + 26: "Auto range on", + 27: "Auto range off", + 28: "Auto range set", +} -EINCPL = { 29: "AC", - 30: "DC", - } +EINCPL = { + 29: "AC", + 30: "DC", +} -ESRCTYP = { 31: "Source off", - 32: "Random noise", - 33: "Burst random", - 34: "Periodic chirp", - 35: "Burst chirp", - 36: "Swept sine", - 37: "Fixed sine", - } +ESRCTYP = { + 31: "Source off", + 32: "Random noise", + 33: "Burst random", + 34: "Periodic chirp", + 35: "Burst chirp", + 36: "Swept sine", + 37: "Fixed sine", +} -ESWPDIR = { 41: "Up", - 42: "Sweep hold", - 43: "Manual sweep", - 44: "Down", - } +ESWPDIR = { + 41: "Up", + 42: "Sweep hold", + 43: "Manual sweep", + 44: "Down", +} -ESWPMOD = { 39: "Linear sweep", - 40: "Log sweep", - } +ESWPMOD = { + 39: "Linear sweep", + 40: "Log sweep", +} EEXTSMPFREQUNT = EXAXIS @@ -245,16 +270,19 @@ ESWPRATEUNT = EXAXIS -EAUGAINREFCH = { 0: "Channel 1", - 1: "Channel 2", - 2: "Not used", - 3: "No channel", - } -EDEMODCH = { 0: "Channel 1", - 1: "Channel 2", - 2: "Both channels", - 3: "No channel", - } +EAUGAINREFCH = { + 0: "Channel 1", + 1: "Channel 2", + 2: "Not used", + 3: "No channel", +} + +EDEMODCH = { + 0: "Channel 1", + 1: "Channel 2", + 2: "Both channels", + 3: "No channel", +} ESRCLVLUNT = EXAXIS @@ -264,24 +292,28 @@ ECPTLGHUNT = EXAXIS -EYCOORD = { 1: "Real", - 2: "Imaginary", - 3: "Linear magnitude", - 4: "Log magnitude", - 5: "dB", - 6: "Nyquist", - 7: "Not used", - 8: "Phase", - 9: "Nichols", - 10: "dBm", - } +EYCOORD = { + 1: "Real", + 2: "Imaginary", + 3: "Linear magnitude", + 4: "Log magnitude", + 5: "dB", + 6: "Nyquist", + 7: "Not used", + 8: "Phase", + 9: "Nichols", + 10: "dBm", +} -EDISPSMP = { 0: "Not sampled", # #displayed elements = total elements - 1: "Half sampled", # #displayed elements = total elements/2 - 2: "Sampled", # #displayed elements < total elements - } -ESCAL = { 0: "X and Y auto scale", - 1: "X fixed, Y auto scale", - 2: "X auto scale, Y fixed", - 3: "X and Y fixed", - } +EDISPSMP = { + 0: "Not sampled", # displayed elements = total elements + 1: "Half sampled", # displayed elements = total elements/2 + 2: "Sampled", # displayed elements < total elements +} + +ESCAL = { + 0: "X and Y auto scale", + 1: "X fixed, Y auto scale", + 2: "X auto scale, Y fixed", + 3: "X and Y fixed", +}
--- a/pygpibtoolkit/HP3562A/mathtools.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/mathtools.py Tue May 01 00:10:23 2018 +0200 @@ -10,12 +10,14 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org + """ import numpy + def thd(spectrum, squared=True, db=True): """ compute THD from a spectrum data, given by a simple 1D data @@ -23,7 +25,7 @@ The result is the couple (fmax, thd), this latter being expressed in 'db' if db is True; if not, in percentage. - + """ n = len(spectrum) # first, find the fundamental frequency @@ -50,6 +52,7 @@ thd = 100.0*numpy.sqrt(thd) return h_freqs2.mean(), thd + def thd_n(spectrum, squared=True, db=True): """ compute THD+N from a spectrum data, given by a simple 1D data @@ -57,12 +60,12 @@ The result is the thdN, expressed in 'db' if db is True; if not, in percentage. - + """ if not squared: spectrum = spectrum**2 fmax = spectrum.argmax() - w = int(fmax/10) # argh + w = int(fmax/10) # argh vmax = spectrum[fmax-w:fmax+w].sum() thd = (spectrum.sum()-vmax)/(vmax) if db: @@ -70,7 +73,3 @@ else: thd = 100.0*numpy.sqrt(thd) return thd - - - -
--- a/pygpibtoolkit/HP3562A/state_decoder.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/state_decoder.py Tue May 01 00:10:23 2018 +0200 @@ -11,8 +11,8 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org state_decoder ============= @@ -20,12 +20,16 @@ Module for decoding the internal state of the HP3562A DSA, using the GPIB command "DSBN" (Dump State BiNary). -This file can be exectued as a python script. Use '-h' for more informations. +This file can be exectued as a python script. Use '-h' for more informations. + """ -from pygpibtoolkit.gpib_utils import format_datablock_header, decode_datablock_header -from pygpibtoolkit.gpib_utils import decode_float, decode_string -from pygpibtoolkit.HP3562A.enum_types import * +from pygpibtoolkit.gpib_utils import ( + format_datablock_header, decode_datablock_header, + decode_float, decode_string) + +from pygpibtoolkit.HP3562A.enum_types import * # noqa + HEADER = [("EMEAS", "Measurement mode", EMEAS, 'h', 2), ("MTYP1", "Measurement 1", EMTYP, 'h', 2), @@ -120,7 +124,8 @@ ("", "Sweep end", decode_float, None, 8), ("", "Carrier frequency", decode_float, None, 8), ] - + + def decode_state(data): """ Decode the data (as generated by the HP3562A DSA in response to a @@ -130,35 +135,36 @@ """ header, idx = decode_datablock_header(data, HEADER) return header - + def main(): import sys - import optparse - opt = optparse.OptionParser("A simple tool for tracing a dumped trace") - opt.add_option('-f', '--filename', default=None, - dest='filename', - help='Output filename. If not set, read from stdin') - opt.add_option('-m', '--mode', default='binary', - dest='mode', - help='Dumping mode (may be "binary" [default], "ascii" or "ansi")', - ) - - options, argv = opt.parse_args(sys.argv) + import argparse + opt = argparse.ArgumentParser("A simple tool for tracing a dumped trace") + opt.add_argument( + '-f', '--filename', default=None, dest='filename', + help='Input filename. If not set, read from stdin') + opt.add_argument( + '-m', '--mode', default='binary', dest='mode', + help='Dumping mode (may be "binary" [default], "ascii" or "ansi")') + options = opt.parse_args() if options.filename is None: - print "Can't deal stdin for now..." + print("Can't deal stdin for now...") sys.exit(1) try: - header = decode_state(open(options.filename, 'rb').read()) - except Exception, e: - print "ERROR: can't read %s an interpret it as a HP3562 trace"%options.filename - print e + with open(options.filename, 'rb') as f: + header = decode_state(f.read()) + except Exception as e: + print("ERROR: can't read %s or interpret it as a HP3562 trace" + % options.filename) + print(e) + raise sys.exit(1) - print format_datablock_header(header, HEADER, 100) - + print(format_datablock_header(header, HEADER, 100)) + + if __name__ == "__main__": main() -
--- a/pygpibtoolkit/HP3562A/test/test_HP3562A.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/test/test_HP3562A.py Tue May 01 00:10:23 2018 +0200 @@ -1,11 +1,17 @@ # -from logilab.common.testlib import TestCase, InnerTest, unittest_main +from unittest import TestCase from pygpibtoolkit.HP3562A.dump_datablock_mockup import HP3562dumper from pygpibtoolkit.gpibcontroller import GPIBController from pygpibtoolkit.gpibmockup import GPIB + class TestHP3562ADeviceManager(TestCase): def test_device(self): c = GPIBController(GPIB()) - self.failUnless(c.detect_devices() == {}) + self.assertEqual(c.detect_devices(), {}) + + +if __name__ == '__main__': + from unittest import main + main()
--- a/pygpibtoolkit/HP3562A/trace_decoder.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP3562A/trace_decoder.py Tue May 01 00:10:23 2018 +0200 @@ -11,8 +11,8 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org trace_decoder ============= @@ -20,62 +20,65 @@ Module for decoding a trace generated by the HP3562A DSA, using the GPIB command "DDBN" (Dump Data BiNary). -This file can be exectued as a python script. Use '-h' for more informations. +This file can be exectued as a python script. Use '-h' for more informations. + """ -import struct + import numpy -from pygpibtoolkit.gpib_utils import format_datablock_header, decode_datablock_header, read_datablock_trace -from pygpibtoolkit.gpib_utils import decode_float, decode_string +from pygpibtoolkit.gpib_utils import ( + format_datablock_header, decode_datablock_header, read_datablock_trace, + decode_float) -from pygpibtoolkit.HP3562A.enum_types import * +from pygpibtoolkit.HP3562A.enum_types import * # noqa -HEADER = [ ("DSPFCT", "Display function", EDSP, 'h', 2), - ("NELTS", 'Number of elements', int, 'h', 2), - ("DSPELTS", 'Displayed elements', int, 'h', 2), - ("NAVG", 'Number of averages', int, 'h', 2), - ("CHSEL", 'Channel selection', ECH, 'h', 2), - ("OVST", 'Overflow status', EOVR, 'h', 2), - ("OVLP", 'Overlap percentage', int, 'h', 2), - ("DOM", 'Domain', EDOM, 'h', 2), - ("VOLTMEAS", 'Volts peak/rms', EVLT, 'h', 2), - ("AMPLUNT", 'Amplitude units', EAMP, 'h', 2), - ("XUNT", 'X axis units', EXAXIS, 'h', 2), - ("AMTHLBL", 'Auto math label', str, 's', 14), - ("TRLBL", 'Trace label', str, 's', 22), - ("EULB1", 'EU label 1', str, 's', 6), - ("EULB2", 'EU label 2', str, 's', 6), - ("VALTYPE", 'Float/Interger', bool, 'h', 2), - ("RVALTYPE", 'Complex/Real', bool, 'h', 2), - ("LIVE", 'Live/Recalled', bool, 'h', 2), - ("MATHRESU", 'Math result', bool, 'h', 2), - ("RVALINPUTTYPE", 'Real/Complex input', bool, 'h', 2), - ("LOGDATA", 'Log/Linear data', bool, 'h', 2), - ("AMTH", 'Auto math', bool, 'h', 2), - ("RTST", 'Real time status', bool, 'h', 2), - ("EMEAS", 'Measurement mode', EMEAS, 'h', 2), - ("", 'Window', EWIN, 'h', 2), - ("", 'Demod type channel 1', EDEMOD, 'h', 2), - ("", 'Demod type channel 2', EDEMOD, 'h', 2), - ("", 'Demod active channel 1', bool, 'h', 2), - ("", 'Demod active channel 2', bool, 'h', 2), - ("", 'Average status', EAVG, 'h', 2), - ("", 'Not used', int, 'hh', 4), - ("", 'Samp freq/2 (real)', decode_float, None, 4), - ("", 'Samp freq/2 (imag)', decode_float, None, 4), - ("", 'Not used', decode_float, None, 4), - ("", 'Delta X-axis', decode_float, None, 4), - ("", 'Max range', decode_float, None, 4), - ("", 'Start time value', decode_float, None, 4), - ("", 'Expon wind const 1', decode_float, None, 4), - ("", 'Expon wind const 2', decode_float, None, 4), - ("", 'EU value chan 1', decode_float, None, 4), - ("", 'EU value chan 2', decode_float, None, 4), - ("", 'Trig delay chan 1', decode_float, None, 4), - ("", 'Trig delay chan 2', decode_float, None, 4), - ("", 'Start freq value', decode_float, None, 8), - ("", 'Start data value', decode_float, None, 8), - ] +HEADER = [("DSPFCT", "Display function", EDSP, 'h', 2), + ("NELTS", 'Number of elements', int, 'h', 2), + ("DSPELTS", 'Displayed elements', int, 'h', 2), + ("NAVG", 'Number of averages', int, 'h', 2), + ("CHSEL", 'Channel selection', ECH, 'h', 2), + ("OVST", 'Overflow status', EOVR, 'h', 2), + ("OVLP", 'Overlap percentage', int, 'h', 2), + ("DOM", 'Domain', EDOM, 'h', 2), + ("VOLTMEAS", 'Volts peak/rms', EVLT, 'h', 2), + ("AMPLUNT", 'Amplitude units', EAMP, 'h', 2), + ("XUNT", 'X axis units', EXAXIS, 'h', 2), + ("AMTHLBL", 'Auto math label', str, 's', 14), + ("TRLBL", 'Trace label', str, 's', 22), + ("EULB1", 'EU label 1', str, 's', 6), + ("EULB2", 'EU label 2', str, 's', 6), + ("VALTYPE", 'Float/Interger', bool, 'h', 2), + ("RVALTYPE", 'Complex/Real', bool, 'h', 2), + ("LIVE", 'Live/Recalled', bool, 'h', 2), + ("MATHRESU", 'Math result', bool, 'h', 2), + ("RVALINPUTTYPE", 'Real/Complex input', bool, 'h', 2), + ("LOGDATA", 'Log/Linear data', bool, 'h', 2), + ("AMTH", 'Auto math', bool, 'h', 2), + ("RTST", 'Real time status', bool, 'h', 2), + ("EMEAS", 'Measurement mode', EMEAS, 'h', 2), + ("", 'Window', EWIN, 'h', 2), + ("", 'Demod type channel 1', EDEMOD, 'h', 2), + ("", 'Demod type channel 2', EDEMOD, 'h', 2), + ("", 'Demod active channel 1', bool, 'h', 2), + ("", 'Demod active channel 2', bool, 'h', 2), + ("", 'Average status', EAVG, 'h', 2), + ("", 'Not used', int, 'hh', 4), + ("", 'Samp freq/2 (real)', decode_float, None, 4), + ("", 'Samp freq/2 (imag)', decode_float, None, 4), + ("", 'Not used', decode_float, None, 4), + ("", 'Delta X-axis', decode_float, None, 4), + ("", 'Max range', decode_float, None, 4), + ("", 'Start time value', decode_float, None, 4), + ("", 'Expon wind const 1', decode_float, None, 4), + ("", 'Expon wind const 2', decode_float, None, 4), + ("", 'EU value chan 1', decode_float, None, 4), + ("", 'EU value chan 2', decode_float, None, 4), + ("", 'Trig delay chan 1', decode_float, None, 4), + ("", 'Trig delay chan 2', decode_float, None, 4), + ("", 'Start freq value', decode_float, None, 8), + ("", 'Start data value', decode_float, None, 8), + ] + def decode_trace(data, idx=0): """ @@ -87,68 +90,70 @@ complex values). """ header, idx = decode_datablock_header(data, HEADER, idx) - return header, read_datablock_trace(data, idx, header["Number of elements"]) + return header, read_datablock_trace( + data, idx, header["Number of elements"]) + def main(): import sys - import optparse - opt = optparse.OptionParser("A simple tool for tracing a dumped trace") - opt.add_option('-f', '--filename', default=None, - dest='filename', - help='Output filename. If not set, read from stdin') - opt.add_option('-m', '--mode', default='binary', - dest='mode', - help='Dumping mode (may be "binary" [default], "ascii" or "ansi")', - ) - opt.add_option('-d', '--display-header', default=False, - action="store_true", - dest="displayheader", - help="Display the trace header") - opt.add_option('-P', '--noplot-trace', default=True, - action="store_false", - dest="plot", - help="Do not display the plot of the trace") - opt.add_option('-x', '--xmode', default='lin', - dest='xmode', - help='X coordinate mode (may be "lin" [default] or "log")') - opt.add_option('-y', '--ymode', default='lin', - dest='ymode', - help='Y coordinate mode (may be "lin" [default], "log" or "db")') - - options, argv = opt.parse_args(sys.argv) + import argparse + opt = argparse.ArgumentParser("A simple tool for tracing a dumped trace") + opt.add_argument( + '-f', '--filename', default=None, dest='filename', + help='Output filename. If not set, read from stdin') + opt.add_argument( + '-m', '--mode', default='binary',dest='mode', + help='Dumping mode (may be "binary" [default], "ascii" or "ansi")') + opt.add_argument( + '-d', '--display-header', default=False, action="store_true", + dest="displayheader", help="Display the trace header") + opt.add_argument( + '-P', '--noplot-trace', default=True, action="store_false", + dest="plot", help="Do not display the plot of the trace") + opt.add_argument( + '-x', '--xmode', default='lin', dest='xmode', + help='X coordinate mode (may be "lin" [default] or "log")') + opt.add_argument( + '-y', '--ymode', default='lin', dest='ymode', + help='Y coordinate mode (may be "lin" [default], "log" or "db")') + options = opt.parse_args() if options.filename is None: - print "Can't deal stdin for now..." + print("Can't deal stdin for now...") sys.exit(1) try: - header, data = decode_trace(open(options.filename, 'rb').read()) - except Exception, e: - print "ERROR: can't read %s an interpret it as a HP3562 trace"%options.filename - print e + with open(options.filename, 'rb') as f: + header, data = decode_trace(f.read()) + except Exception as e: + print("ERROR: can't read %s an interpret it as a HP3562 trace" + % options.filename) + print(e) sys.exit(1) if options.displayheader: - print format_datablock_header(header, HEADER, 100) + print(format_datablock_header(header, HEADER, 100)) + f0 = header['Start freq value'] dx = header['Delta X-axis'] n = header['Number of elements'] - x = numpy.linspace(f0, f0+dx*n, len(data)) + x = numpy.linspace(f0, f0+dx*n, len(data)) y = data.copy() if options.plot: import pylab if options.ymode != "lin": - minv = min(y[y>0]) - y[y==0] = minv + minv = min(y[y > 0]) + y[y == 0] = minv y = numpy.log10(y) if options.ymode == "db": - y = y*10 + y = y * 10 pylab.ylabel('db') pylab.grid() pylab.plot(x, y) pylab.xlabel('frequency') - pylab.show() + pylab.show() return header, x, y + if __name__ == "__main__": h, x, y = main()
--- a/pygpibtoolkit/HP8904.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/HP8904.py Tue May 01 00:10:23 2018 +0200 @@ -10,33 +10,32 @@ # 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. -""" Copyright (c) 2007-2009 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org """ -import mx.DateTime as dt - -from pygpibtoolkit.pygpib import Constants, Command -from pygpibtoolkit.pygpib import Mode, ModeCommand +from pygpibtoolkit.pygpib import ModeCommand from pygpibtoolkit.pygpib import VoltageValue, FrequencyValue from pygpibtoolkit.pygpib import FloatUnitValue - from pygpibtoolkit.pygpib import SimpleMode from pygpibtoolkit.gpibcontroller import AbstractGPIBDevice, deviceRegister + class _VoltageValue(VoltageValue): - _units = "VL","MV","UV" + _units = "VL", "MV", "UV" + class APA(_VoltageValue): "CHAN A AMP - Channel A amplitude" -class APB(_VoltageValue): +class APB(_VoltageValue): # noqa "CHAN B AMP - Channel B amplitude" -class APC(_VoltageValue): +class APC(_VoltageValue): # noqa "CHAN C AMP - Channel C amplitude" -class APD(_VoltageValue): +class APD(_VoltageValue): # noqa "CHAN D AMP - Channel D amplitude" + class Backlight(SimpleMode): "Backlight" @@ -45,7 +44,7 @@ class _PerOutputMode(SimpleMode): - + def __init__(self): self._cmds = [] for cmdname, cmd in self.__class__.__dict__.items(): @@ -58,7 +57,7 @@ assert self._prefix+value in self._cmds return self._prefix+value, value - + class Filter1(_PerOutputMode): "Filter for output 1" _prefix = "FS1" @@ -67,10 +66,11 @@ LO = ModeCommand("Gaussian (low overshoot)", "GAUSS.") AU = ModeCommand("Automatic", "AUTO") + class Filter2(Filter1): "Filter for output 2" _prefix = "FS2" - + class Float1(_PerOutputMode): "Float Control for output 1" @@ -78,45 +78,53 @@ ON = ModeCommand("On", "ON") OF = ModeCommand("Off", "OFF") + class Float2(Float1): "Float Control for output 2" _prefix = "FC2" + class _FrequencyValue(FrequencyValue): - _units = ['HZ','KZ'] - + _units = ['HZ', 'KZ'] + + class FRA(_FrequencyValue): "CHAN A FRQ - Channel A frequency" -class FRB(_FrequencyValue): +class FRB(_FrequencyValue): # noqa "CHAN B FRQ - Channel B frequency" -class FRC(_FrequencyValue): +class FRC(_FrequencyValue): # noqa "CHAN C FRQ - Channel C frequency" -class FRD(_FrequencyValue): +class FRD(_FrequencyValue): # noqa "CHAN D FRQ - Channel D frequency" + class OutputControl1(_PerOutputMode): "Output 1" _prefix = "OO1" ON = ModeCommand("On", "ON") OF = ModeCommand("Off", "OFF") + class OutputControl2(OutputControl1): "Output 2" _prefix = "OO2" + class _PhaseValue(FloatUnitValue): _units = ['DG', 'RD'] _name = "phase" + class PHA(_PhaseValue): "CHAN A PHA - Channel A phase" -class PHB(_PhaseValue): +class PHB(_PhaseValue): # noqa "CHAN B PHA - Channel B phase" -class PHC(_PhaseValue): +class PHC(_PhaseValue): # noqa "CHAN C PHA - Channel C phase" -class PHD(_PhaseValue): +class PHD(_PhaseValue): # noqa "CHAN D PHA - Channel D phase" + class _Waveform(_PerOutputMode): "waveform" SI = ModeCommand('Sine', 'SINE') @@ -126,19 +134,20 @@ NS = ModeCommand('Noise', 'NOIS') DC = ModeCommand('DC', 'DC') + class WaveformA(_Waveform): "CHAN A FORM - Channel A waveform" _prefix = "WFA" -class WaveformB(_Waveform): +class WaveformB(_Waveform): # noqa "CHAN B FORM - Channel B waveform" _prefix = "WFB" -class WaveformC(_Waveform): +class WaveformC(_Waveform): # noqa "CHAN C FORM - Channel C waveform" _prefix = "WFC" -class WaveformD(_Waveform): +class WaveformD(_Waveform): # noqa "CHAN D FORM - Channel D waveform" _prefix = "WFD" - + class _Destination(_PerOutputMode): "Destination" @@ -150,13 +159,14 @@ OC1 = ModeCommand('OC1', 'OC1') OC2 = ModeCommand('OC2', 'OC2') OF = ModeCommand('OF', 'OF') - + + class HP8904Device(AbstractGPIBDevice): - _accepts = ["^(?P<model>HP *8904A).*$",] + _accepts = ["^(?P<model>HP *8904A).*$"] _idn = "ID" def __init__(self, idn, address, controller): super(HP8904Device, self).__init__(idn, address, controller) - + deviceRegister.register_manager(HP8904Device)
--- a/pygpibtoolkit/__init__.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/__init__.py Tue May 01 00:10:23 2018 +0200 @@ -10,6 +10,6 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/detect.py Tue May 01 00:10:23 2018 +0200 @@ -0,0 +1,53 @@ +#!/usr/bin/python +# 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. +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org +""" +import sys +import signal +import time + +from pygpibtoolkit.gpibcontroller import GPIBController +from pygpibtoolkit.prologix import GPIB + + +def main(): + import argparse + opt = argparse.ArgumentParser( + "A simple tool for detecting connected GPIB devices") + opt.add_argument( + '-d', '--device', default="/dev/ttyUSB0", + dest="device", + help="Device of connected Prologix GPIB bundle [/dev/ttyUSB0]",) + options = opt.parse_args(sys.argv) + + print("Detecting GPIB devices on the bus. Please wait until completion.") + cnx = GPIB(device=options.device) + c = GPIBController(cnx) + + signal.signal(signal.SIGINT, c.stop) + signal.signal(signal.SIGQUIT, c.stop) + + time.sleep(1) + devices = c.detect_devices() + c.stop() + + print("GPIB devices:") + for k in sorted(devices.keys()): + print("%-3d: %s" % (k, devices[k])) + return c, devices + + +if __name__ == "__main__": + main()
--- a/pygpibtoolkit/gpib_utils.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/gpib_utils.py Tue May 01 00:10:23 2018 +0200 @@ -11,8 +11,8 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org Several utility functions for GPIB data conversions """ @@ -20,6 +20,7 @@ import re import numpy + ######################################## # internal binary types decoders @@ -43,27 +44,30 @@ i3 = i3*2**(-15) i4 = i4 * 2**(-38) return (i1+i2+i3+i4)*2**(e-15) - + + def decode_string(s): """ Decode a string from the HP binay representation. """ - nb = ord(s[0]) + nb = s[0] s = s[1:nb+2] - r = "" + r = [] # XXX why do we need to do this? It's not described in the manual... for c in s: - r += chr(ord(c) & 0x7F) - return r + r.append(chr(c & 0x7F)) + return ''.join(r) + ### # Datablock useful functions def format_datablock_header(header, head_struct, columns=80): """ - Pretty print a data block (trace, state or coord) + Pretty print a data block (trace, state or coord) """ - bool_re = re.compile(r'((?P<before>.*) )?(?P<flag>\w+/\w+)( (?P<after>.*))?') - + bool_re = re.compile( + r'((?P<before>.*) )?(?P<flag>\w+/\w+)( (?P<after>.*))?') + todisp = [] for row in head_struct: pname = row[0] @@ -72,7 +76,7 @@ if typ is None: continue val = header.get(key, "N/A") - if isinstance(val, basestring): + if isinstance(val, str): val = repr(val) elif typ is bool and isinstance(val, typ): m = bool_re.match(key) @@ -87,34 +91,37 @@ val = d['flag'].split('/')[not val] else: val = str(val) - else: + else: val = str(val) - todisp.append((key+":", val)) + todisp.append((key + ":", val)) maxk = max([len(k) for k, v in todisp]) maxv = max([len(v) for k, v in todisp]) - fmt = "%%-%ds %%-%ds"%(maxk, maxv) - w = maxk+maxv+4 - ncols = columns/w + fmt = "%%-%ds %%-%ds" % (maxk, maxv) + w = maxk + maxv + 4 + ncols = columns // w if ncols: - nrows = len(todisp)/ncols + nrows = len(todisp) // ncols else: nrows = len(todisp) ncols = 1 - res = "" + res = [] for i in range(nrows): - res += "| ".join([fmt%todisp[j*nrows+i] for j in range(ncols)]) + "\n" - return res + res.append(("| ".join( + fmt % todisp[j * nrows + i] for j in range(ncols))).rstrip()) + return '\n'.join(res) + -def decode_datablock_header(data, header_struct, idx=0): +def decode_datablock_header(data, header_struct, idx=0): d = data - if d[idx:].startswith('#'): + if d[idx:idx + 1] == b'#': # we have a preliminary header here... - typ = d[idx:idx+2] - assert typ == "#A" + typ = d[idx:idx + 2] + assert typ == b"#A" idx += 2 totlen = struct.unpack('>h', d[idx:idx+2])[0] idx += 2 - tt=0 + print(' header at %s for %s' % (idx, totlen)) + tt = 0 header = {} for i, (cmd, nam, dtype, fmt, nbytes) in enumerate(header_struct): if dtype is None: @@ -135,10 +142,11 @@ idx += nbytes return header, idx + def read_datablock_trace(data, idx, nelts): - assert len(data[idx:]) >= (nelts*4), "data[idx:] is too small (%s for %s)"%(len(data[idx:]), (nelts*4)) + assert len(data[idx:]) >= (nelts*4), "data[idx:] is too small (%s for %s)" % (len(data[idx:]), (nelts*4)) resu = [] for i in range(nelts): - resu.append(decode_float(data[idx: idx+4])) + resu.append(decode_float(data[idx: idx + 4])) idx += 4 return numpy.array(resu, dtype=float)
--- a/pygpibtoolkit/gpibcontroller.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/gpibcontroller.py Tue May 01 00:10:23 2018 +0200 @@ -11,8 +11,8 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org A general purpose GPIB controller based on prologix GPIB device """ @@ -24,9 +24,10 @@ from inspect import isclass from serial.serialutil import SerialException -from prologix import GPIB, GPIB_CONTROLLER, GPIB_DEVICE +from pygpibtoolkit.prologix import GPIB, GPIB_CONTROLLER, GPIB_DEVICE from pygpibtoolkit.pygpib import AbstractCommand + class AbstractGPIBDeviceMetaclass(type): def __new__(mcs, name, bases, classdict): # Automatically add commands to Device classes. @@ -45,15 +46,14 @@ setattr(new_cls, pname, p) for subattr in p._cmds: def getter(self, cmd=subattr): - print "self=",self ret = self.send_command(cmd) if not ret: ret = "" return ret setattr(new_cls, subattr, property(getter)) - return new_cls + class AbstractGPIBDevice(object): __metaclass__ = AbstractGPIBDeviceMetaclass _accepts = [] @@ -65,42 +65,44 @@ if m: return m.group('model') return False - #return idn in cls._accepts - + # return idn in cls._accepts + def __init__(self, idn, address, controller): self._idn = idn self._address = address self._controller = controller self._use_cache = True - + self._cache = {} for pname, param in self.__class__.__dict__.items(): - if isinstance(param, AbstractCommand) and not param._readonly and param._cached: + if (isinstance(param, AbstractCommand) + and not param._readonly + and param._cached): self._cache[pname] = param._init_value def use_cache(self, use=None): if use is None: return self._use_cache self._use_cache = bool(use) - + def _get(self, name): if self._use_cache and name in self._cache and \ self._cache[name] is not None: return self._cache[name] - - param = getattr(self.__class__, name) + + param = getattr(self.__class__, name) value = param.get_value_from_device(self) if name in self._cache: self._cache[name] = value return value - + def _set(self, name, value): - param = getattr(self.__class__, name) + param = getattr(self.__class__, name) res, value = param.send_value_to_device(self, value) if name in self._cache: self._cache[name] = value return res - + def manage_srq(self, statusbyte): pass @@ -115,8 +117,8 @@ Read currently available DATA in buffer """ return self.send_command('') - - + + class GPIBDeviceRegister(object): def __init__(self): self._registry = [] @@ -134,19 +136,23 @@ return [mgr._idn for mgr in self._registry if mgr._idn] def __str__(self): - msg = "<GPIBDeviceRegister: %s managers\n"%len(self._registry) + msg = "<GPIBDeviceRegister: %s managers\n" % len(self._registry) for mgr in self._registry: - msg += " %s: %s\n"%(mgr.__name__, ", ".join(mgr._accepts)) + msg += " %s: %s\n" % (mgr.__name__, ", ".join(mgr._accepts)) msg += ">" return msg - + + deviceRegister = GPIBDeviceRegister() + class GenericGPIBDevice(AbstractGPIBDevice): _idn = "*IDN?" - + + deviceRegister.register_manager(GenericGPIBDevice) + class GPIBController(object): """ The main GPIB Controller In Charge. @@ -162,7 +168,7 @@ with GPIB and device commands, which are executed ASAP (ie. as soon as the GPIB bus if free and the device states itself as ready.) - + """ def __init__(self, gpibcnx=None, controller_address=21): self._address = controller_address @@ -170,11 +176,11 @@ self._devices = {} self._debug = False self._setup_threading_system() - + def __del__(self): - print "deleting controller" + # print "deleting controller" self._stop.set() - + def _setup_threading_system(self): self._n_cmds = 0 self._n_cmds_lock = threading.RLock() @@ -189,23 +195,23 @@ self._cnx_thread.start() self._suspended = False self._loop_interrupter.set() - + def _check_srq(self): if self._cnx and self._cnx.check_srq(): addrs = sorted(self._devices.keys()) polled = self._cnx.poll(addrs) for add in addrs: if polled[add] & 0x40: - #print "device %s (#%s) requested attention"%(self._devices[add]._idn, add) + # print "device %s (#%s) requested attention"%(self._devices[add]._idn, add) # TODO: check what to do... self._devices[add].manage_srq(polled[add]) - + def _cnx_loop(self): while 1: if self._debug: sys.stderr.write('.') if self._stop.isSet(): - print "_stop set, exiting" + print("_stop set, exiting") return while not self._loop_interrupter.isSet(): if self._debug: @@ -249,25 +255,25 @@ def suspend(self, *args): while not self._loop_interrupter.isSet(): self._loop_interrupter.wait() - print "Suspending main connection loop" + print("Suspending main connection loop") self._suspended = True self._loop_interrupter.clear() def resume(self, *args): if not self._suspended: return - print "Resuming main connection loop" + print("Resuming main connection loop") self._suspended = False self._loop_interrupter.set() - + def send_command(self, addr, cmd, sync=True, cb=None): - #print "SEND CMD %s"%repr(cmd) + # print "SEND CMD %s"%repr(cmd) if cb is not None and callable(cb): sync = False if sync and self._loop_interrupter.isSet(): - print "WARNING: send synchronized command when cnx is locked" - #sync = False - + print("WARNING: send synchronized command when cnx is locked") + # sync = False + self._n_cmds_lock.acquire() self._n_cmds += 1 n_cmd = self._n_cmds @@ -276,7 +282,7 @@ cond = self._cmd_condition cond.acquire() if sync: - cb = threading.Event() + cb = threading.Event() self._cmd_queue[n_cmd] = (addr, cmd, cb) cond.notify() cond.release() @@ -289,7 +295,7 @@ resu = self._results_queue.pop(n_cmd) cond.release() return resu - + def detect_devices(self): """ Perform a Serial Poll on all addresses to detect alive devices @@ -309,21 +315,26 @@ if idn: self.register_device(address, idn) devices[address] = str(idn) - print "registered device", idn + print("registered device %s" % idn) break else: # redo a spoll, it should have set the err bit poll = self._cnx.poll(address) - if (isinstance(poll, dict) and address not in poll) or (not poll & 0x20): # 0x20 == ERR bit - print "WARNING: device %d did not answer to a %s command by setting its ERR bit"%(address, id_str) + if ((isinstance(poll, dict) + and address not in poll) + or (not poll & 0x20)): # 0x20 == ERR bit + print("WARNING: device %d did not answer to a " + "%s command by setting its ERR bit" % + (address, id_str)) devices[address] = "UNKNOWN" else: - print "WARNING: Can't retrieve IDN of device at address ", address + print("WARNING: Can't retrieve IDN of device at " + "address %s" % address) devices[address] = "UNKNOWN" finally: self._loop_interrupter.set() return devices - + def register_device(self, address, idn): """ Register a device manager for device at given GPIB @@ -335,15 +346,16 @@ self._devices[address] = devicemgr return devicemgr else: - print "WARNING: can't find a manager for", repr(idn) - #print deviceRegister._registry + print("WARNING: can't find a manager for %r" % idn) + # print deviceRegister._registry def idn(self, address): """ Query identity of the addressed device. """ - return self.send_command(address, self._devices[address].__class__._idn).strip() - + return self.send_command( + address, self._devices[address].__class__._idn).strip() + def status(self, address): """ Query status byte for device at given address @@ -355,7 +367,7 @@ return self._cnx.poll(address) finally: self._loop_interrupter.set() - + def get_devicemanager(self, address): return self._devices.get(address)
--- a/pygpibtoolkit/prologix.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/prologix.py Tue May 01 00:10:23 2018 +0200 @@ -10,51 +10,53 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org prologix ======== Module defining a communication object to talk to Prologix USB-GPIB controler. +""" -""" import sys import serial import time -from pygpibtoolkit import pygpib from pygpibtoolkit.pygpib import ConnectionError GPIB_CONTROLLER = 1 GPIB_DEVICE = 0 -class GPIB(object): + +class GPIB: _retries = 15 + def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1, - address=0, mode=1): + address=0, mode=1): """ Create a new GPIB controller for the Prologix USB-GPIB device - located on serial device 'device'. + located on serial device 'device'. """ - self._cnx = serial.Serial(port=device, baudrate=baudrate, timeout=timeout) + self._cnx = serial.Serial(port=device, baudrate=baudrate, + timeout=timeout) self._timeout = timeout try: res = self._cnx.readlines() - if res: # empty evetual read buffer - print "there where pending stuffs in buffer", repr(res) + if res: # empty evetual read buffer + print("there where pending stuffs in buffer %r" % res) self.set_mode(1) self.set_address(address) self._set_cmd('auto', 0) self.set_mode(mode) - except Exception, e: - print "Humm, something went wrong", e - + except Exception as e: + print("Humm, something went wrong: %s" % e) + def set_address(self, address, check=True): """ Set the address of the GPIB device: - + - if the device is the Controller In Charge, this is the address of the device commands are sent to, @@ -62,12 +64,12 @@ """ self._set_cmd('addr', address, check) self._address = address - #self._set_cmd('auto', 0) - + # self._set_cmd('auto', 0) + def set_mode(self, mode): """ Set GPIB device mode to 'mode': - + - GPIB_CONTROLLER: set the device as the Controller In Charge on the GPIB bus @@ -87,7 +89,7 @@ def set_device(self): """ - Set the GPIB device as a simple device on the GPIB bus. + Set the GPIB device as a simple device on the GPIB bus. """ self.set_mode(0) @@ -101,24 +103,24 @@ if address is not None: self.set_address(address) self._cnx.write(cmd+';\r') - time.sleep(self._timeout) # required? + time.sleep(self._timeout) # required? return self.read_eoi() - + def read_eoi(self, address=None): """ Read the HPIB buffer from device, till EOI is performed, or timeout. """ if address is not None: self.set_address(address, check=False) - self._cnx.write('++read eoi\r') # idem + self._cnx.write('++read eoi\r') # idem ret = "" i = 0 while not ret.endswith('\r\n') and i<3: ret += ''.join(self._cnx.readlines()) - time.sleep(self._timeout) # required? + time.sleep(self._timeout) # required? i += 1 return ''.join(ret) - + def check_srq(self): """ Check the SRQ line @@ -126,10 +128,10 @@ assert self._mode == 1, "must be the Controller In Charge" ret = self._cnx.readline().strip() if ret: - print "garbage:", ret + print("garbage: %s" % ret) self._cnx.write('++srq\r') ret = self._cnx.readline().strip() - if ret in ["0","1"]: + if ret in "01": return bool(int(ret)) return None @@ -139,28 +141,28 @@ """ if address is not None: self.set_address(address, check=False) - self._cnx.write('++trg\r') # idem - + self._cnx.write('++trg\r') # idem + def poll(self, addresses=None, verbose=False): """ Poll every address, and return a dictionnary - {add: status, ...} - """ - assert self._mode == 1, "must be the Controller In Charge" + {add: status, ...} + """ + assert self._mode == 1, "must be the Controller In Charge" only_one = False if addresses is None: addresses = range(31) if not isinstance(addresses, (list, tuple)): addresses = [addresses] only_one = True - if len(addresses)==0: + if not addresses: return None if verbose: sys.stderr.write('polling ') dico = {} for add in addresses: - self._cnx.write('++spoll %d\r'%add) + self._cnx.write('++spoll %d\r' % add) time.sleep(0.1) ret = self._cnx.readline().strip() if ret: @@ -170,15 +172,17 @@ else: if verbose: sys.stderr.write('.') - - time.sleep(0.30) # need to wait at least 150ms (not enough on prologix) + + # need to wait at least 150ms (not enough on prologix) + time.sleep(0.30) + if verbose: sys.stderr.write('\n') self.set_address(self._address) if only_one and dico: return dico.values()[0] return dico - + def _read(self): for i in range(self._retries): rdata = self._cnx.readline() @@ -188,21 +192,20 @@ return rdata def _set_cmd(self, cmd, value, check=True): - self._cnx.write('++%s %d\r'%(cmd, value)) + self._cnx.write('++%s %d\r' % (cmd, value)) if check: - self._cnx.write('++%s\r'%(cmd)) + self._cnx.write('++%s\r' % (cmd)) rval = self._read().strip() if not rval.isdigit() or int(rval) != value: - raise ConnectionError("Can't set GPIB %s to %s [ret=%s]"%(cmd, value, repr(rval))) + raise ConnectionError("Can't set GPIB %s to %s [ret=%s]" % ( + cmd, value, repr(rval))) def reset(self): """ Perform a reset of the USB device - + """ - print "Resetting GPIB controller" + print("Resetting GPIB controller") self._cnx.write('++rst\r') - print "Must wait for 5 seconds" + print("Must wait for 5 seconds") time.sleep(5) - -
--- a/pygpibtoolkit/pygpib.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/pygpib.py Tue May 01 00:10:23 2018 +0200 @@ -10,45 +10,50 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +"""Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org gpib: create serial connection to GPIB-USB device (Prologix is the only supported device for now). + """ import re -import serial -from serial.serialutil import SerialException -import time -from pygpibtoolkit.tools import AbstractRegister +from pygpibtoolkit.tools import AbstractRegister # noqa import operator + class ConnectionError(Exception): pass -class Condition(object): + +class Condition: def __call__(self, device): return True + def __and__(self, cond): assert isinstance(cond, Condition) return _ComposedCondition(operator.__and__, self, cond) + def __or__(self, cond): assert isinstance(cond, Condition) return _ComposedCondition(operator.__or__, self, cond) - + + class _ComposedCondition(Condition): def __init__(self, op, *args): self._conditions = list(args[:]) - self._reduc_op = op + self._reduc_op = op for cond in args: assert isinstance(cond, Condition) if isinstance(cond, _ComposedCondition) and cond._reduc_op == op: i = self._conditions.index(cond) self._conditions[i:i+1] = cond._conditions + def __call__(self, device): return reduce(self._reduc_op, [f(device) for f in self._conditions]) - -class Constants(object): + + +class Constants: def __init__(self): self.constants = {} self.descriptions = {} @@ -58,7 +63,7 @@ self.constants[v] = k self.rev_constants[k] = v self.descriptions[v] = m - + def __getitem__(self, k): if isinstance(k, basestring): return self.rev_constants[k] @@ -70,18 +75,20 @@ k = self.rev_constants[k] return self.descriptions[k] -class MODE(Constants): + +class MODE(Constants): _constants = [(1, "CONTROLLER", "Set device as Controller in Charge"), (0, "DEVICE", "Set device as simple listener"), ] -class ModeCommand(object): +class ModeCommand: def __init__(self, description, name, condition=None): self.name = name self.description = description self.condition = condition - -class AbstractCommand(object): + + +class AbstractCommand: """ Base class for HPIB command description. @@ -92,7 +99,7 @@ _init_value = None _cached = True _cmds = [] - + def __get__(self, instance, owner): if instance is None: return self @@ -102,7 +109,7 @@ if instance is None: return self return instance._set(self.__class__.__name__, value) - + def get_value_from_device(self, device): cmd = self.build_get_cmd() value = device.send_command(cmd) @@ -113,24 +120,25 @@ cmd, value = self.build_set_cmd(value) res = device.send_command(cmd) return res, self.convert_to(value) - + def build_get_cmd(self): return self.__class__.__name__ def build_set_cmd(self, *value): - raise ValueError, "Can't set value for command '%s'"%self.__class__.__name__ - + raise ValueError( + "Can't set value for command '%s'" % self.__class__.__name__) + def convert_from(self, *value): return None def convert_to(self, *value): return None - + class Command(AbstractCommand): """pure command """ - + class AbstractValue(Command): _readonly = False @@ -140,39 +148,44 @@ def build_set_cmd(self, *value): value = self.convert_to(*value) - cmd = "%s %s"%(self.__class__.__name__, value) + cmd = "%s %s" % (self.__class__.__name__, value) return cmd, value - + def convert_to(self, *value): if value: return str(value[0]) return "" - + def convert_from(self, *value): if value: return self._type(value[0].strip()) return None - + + class BoolValue(AbstractValue): _type = bool + def convert_from(self, *value): if value: - return value[0] and value[0].lower() in ['1','true','yes','on'] + return value[0] and value[0].lower() in ['1', 'true', 'yes', 'on'] return False - + def convert_to(self, *value): if value: - return value[0] and "1" or "0" - return "" # XXX is it correct? - + return value[0] and "1" or "0" + return "" # XXX is it correct? + + class IntValue(AbstractValue): _type = int + def convert_from(self, *value): if value: - # int is resturned as a string representing a float + # int is resturned as a string representing a float return self._type(float(value[0].strip())) return None + class flag(int): def __new__(cls, val, constants): val = int.__new__(cls, val) @@ -181,40 +194,50 @@ if name not in ['', 'N/A']: setattr(val, name, v) return val - + def __str__(self): - return '%s <' + '|'.join([x[1] for x in self._constants if x[0]&self]) + ">" + return ('%s <' + + '|'.join(x[1] for x in self._constants if x[0] & self) + + ">") + def flags(self): - return [x[1] for x in self._constants if x[0] & (self and x[1]) not in ['','N/A']] - + return [x[1] for x in self._constants + if x[0] & (self and x[1]) not in ['', 'N/A']] + def descriptions(self): - return [x[2] for x in self._constants if (x[0] & self) and x[1] not in ['','N/A']] + return [x[2] for x in self._constants + if (x[0] & self) and x[1] not in ['', 'N/A']] + class Flag(IntValue): _readonly = True _constants = [] _type = flag + def convert_from(self, *value): if value: return self._type(float(value[0].strip()), _constants) return None - + + class FloatValue(AbstractValue): _type = float + class PercentageValue(FloatValue): pass #TODO + class FloatUnitValue(FloatValue): """ A Float value with unit (frequency, etc.) """ def convert_to(self, *value): if value: - if len(value)==1: - if isinstance(value[0], basestring): + if len(value) == 1: + if isinstance(value[0], str): value = value[0].strip() - reunits = '(?P<unit>'+'|'.join(self._units)+')' + reunits = '(?P<unit>' + '|'.join(self._units) + ')' reexpr = r'(?P<value>[-]?[0-9]+([.][0-9]+)?) *' + reunits m = re.match(reexpr, value) try: @@ -224,8 +247,8 @@ else: unit = self._units[0] freq = float(value) - except Exception, e: - raise ValueError, "Can't interpret %s as a %s"%(repr(value), self._name) + except Exception as e: + raise ValueError("Can't interpret %r as a %s" % (value, self._name)) else: freq = float(value[0]) unit = self._units[0] @@ -233,37 +256,45 @@ freq = float(value[0]) unit = value[1] else: - raise ValueError, "Can't interpret %s as a %s"%(repr(value), self._name) - assert unit in self._units, "Unit is not correct (%s)"%repr(unit) - return "%s%s"%(freq, unit) - return "" # XXX is it correct? + raise ValueError("Can't interpret %r as a %s" % (value, self._name)) + assert unit in self._units, "Unit is not correct (%r)" % unit + return "%s%s" % (freq, unit) + return "" # XXX is it correct? + class FrequencyValue(FloatUnitValue): - _units = ['Hz','kHz','mHz',] + _units = ['Hz', 'kHz', 'mHz',] _name = "frequency" + class VoltageValue(FloatUnitValue): - _units = ['V','mV',] + _units = ['V', 'mV',] _name = "voltage" - + + class DurationValue(FloatUnitValue): - _units = ['sec','msec','usec','min'] + _units = ['sec', 'msec', 'usec', 'min'] _name = "duration" + class StringValue(AbstractValue): _type = str + def convert_to(self, *value): if value: - return "'%s'"%str(value[0]) + return "'%s'" % str(value[0]) return "''" + class EnumValue(StringValue): - _values = [] + _values = () + def convert_to(self, *value): if value: assert value[0] in self._values - return "%s"%self._values.index(value[0]) - return "" # XXX + return "%s" % self._values.index(value[0]) + return "" # XXX + class SimpleMode(AbstractCommand): """ @@ -286,7 +317,7 @@ class WriteOnlyMode(SimpleMode): def get_value_from_device(self, device): raise ValueError("can't retrieve mode value from device") - + def __set__(self, instance, value): if instance is None: return self @@ -307,7 +338,8 @@ def get_value_from_device(self, device): value = self.get_mode(device) return value - + + # TODO # class STATUS_BYTE(Constants): # # IEEE 488.2 Status Byte constants @@ -333,4 +365,3 @@ # OPC = 0x01 # Operation Complete: device has completed any pending # # operation (ready to accept new commands). This bit is # # generated in response to a OPC command. -
--- a/pygpibtoolkit/tools.py Thu Apr 02 16:58:24 2009 +0200 +++ b/pygpibtoolkit/tools.py Tue May 01 00:10:23 2018 +0200 @@ -10,62 +10,68 @@ # 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. -""" Copyright (c) 2007-2008 David Douard (Paris, FRANCE). -http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr +""" Copyright (c) 2007-2018 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@sdfa3.org Helper functions and classes """ import re -def str_num_cmp(s1,s2): + +def cmp(a, b): + return (a > b) - (a < b) + + +def str_num_cmp(s1, s2): """ string comparator function that will put 'toto_10' after 'toto_2' Also works for strings like 'toto_1_et_23er25'. """ r = re.compile(r'((?<=\d)\D+|(?<=\D)\d+)') - r1= r.split(s1) - r2= r.split(s2) - r1=[not x.isdigit() and x or int(x) for x in r1 if x!=''] - r2=[not x.isdigit() and x or int(x) for x in r2 if x!=''] - return cmp(r1,r2) + r1 = r.split(s1) + r2 = r.split(s2) + r1 = [not x.isdigit() and x or int(x) for x in r1 if x] + r2 = [not x.isdigit() and x or int(x) for x in r2 if x] + return cmp(r1, r2) -class AbstractRegister(object): +class AbstractRegister: _instance = None _registered_type = None + def __new__(cls): # implements a singleton if cls._instance is None: - #debug('Instanciating %s', cls.__name__) + # debug('Instanciating %s', cls.__name__) cls._instance = super(AbstractRegister, cls).__new__(cls) cls._instance.registered = {} cls._instance.accepts = set() return cls._instance - + def add(self, cls): assert issubclass(cls, self._registered_type) if cls is self._registered_type: return if cls._accepts is None: return - #assert isinstance(cls._accepts, (basestring, tuple)) - - #debug("Registerered %s for %s", cls.__name__) + # assert isinstance(cls._accepts, (basestring, tuple)) + + # debug("Registerered %s for %s", cls.__name__) if not isinstance(cls._accepts, tuple): cls._accepts = (cls._accepts,) for key in cls._accepts: key = self._get_typ(key) - #debug(" new key = %s", key) + # debug(" new key = %s", key) self.registered.setdefault(key, []).append(cls) self.accepts.add(key) def _get_typ(self, typ): - if not isinstance(typ, basestring): + if not isinstance(typ, str): if not isinstance(typ, type): return None typ = typ.__name__ return typ - + def __contains__(self, val): val = self._get_typ(val) return val in self.accepts @@ -75,14 +81,14 @@ if not isinstance(typ, type): typ = typ.__class__ name = typ.__name__ - #debug("Looking a widget for %s", typ.__name__) + # debug("Looking a widget for %s", typ.__name__) orig_typ = typ while typ is not None: if typ.__name__ in self.registered: for w in self.registered[typ.__name__]: if w._filter is None or w._filter(item): - #debug("Widget for %s is %s", typ.__name__, w) - return w#self.registered[typ.__name__] + # debug("Widget for %s is %s", typ.__name__, w) + return w # self.registered[typ.__name__] if typ.__bases__: typ = typ.__bases__[0] if typ == object:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.py Tue May 01 00:10:23 2018 +0200 @@ -0,0 +1,17 @@ +# +from setuptools import setup, find_packages + +setup(name="pygpibtoolkit", + author='David Douard', + packages=find_packages(), + version='0.1.0', + install_requires=[ + 'pyserial', 'numpy', 'matplotlib'], + entry_points={'console_scripts': [ + 'pygpib-detect=pygpibtoolkit.detect:main', + 'hp3562-coord=pygpibtoolkit.HP3562A.coord_decoder:main', + 'hp3562-state=pygpibtoolkit.HP3562A.state_decoder:main', + 'hp3562-trace=pygpibtoolkit.HP3562A.trace_decoder:main', + 'hp3562-dump=pygpibtoolkit.HP3562A.dump_datablock:main', + ]} + )