# HG changeset patch # User David Douard # Date 1525126223 -7200 # Node ID 96e30b092f70f95523884070bcea2b757d90e165 # Parent b55977dcc3111879a8b6118ba4e9e15ba61895e2 [py3k] beginning to port to py3k also write a proper setuptools based setup.py and convert some bin/* scripts as entry_points. diff -r b55977dcc311 -r 96e30b092f70 README --- 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. diff -r b55977dcc311 -r 96e30b092f70 bin/dump_datablock --- 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() diff -r b55977dcc311 -r 96e30b092f70 bin/gpib_detect --- 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() - diff -r b55977dcc311 -r 96e30b092f70 bin/read_coord --- 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() diff -r b55977dcc311 -r 96e30b092f70 bin/read_state --- 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() diff -r b55977dcc311 -r 96e30b092f70 bin/read_trace --- 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() diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3456.py --- 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"^(?PHP3456A)$",] - _idn = None # cannot ask device its model number or version + _accepts = [r"^(?PHP3456A)$", ] + _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) diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/HP356X.py --- 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"^(?PHP *356[23][ABCD]).*$",] + _accepts = [r"^(?PHP *356[23][ABCD]).*$", ] _idn = "ID?" + def manage_srq(self, statusbyte): - print "Managing SRQ", statusbyte - + print("Managing SRQ: %s" % statusbyte) + + deviceRegister.register_manager(HP356XDevice) diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/__init__.py --- 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 diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/coord_decoder.py --- 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[y0: - 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 - diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/enum_types.py --- 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", +} diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/mathtools.py --- 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 - - - - diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/state_decoder.py --- 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() - diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/test/test_HP3562A.py --- 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() diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP3562A/trace_decoder.py --- 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() diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/HP8904.py --- 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 = ["^(?PHP *8904A).*$",] + _accepts = ["^(?PHP *8904A).*$"] _idn = "ID" def __init__(self, idn, address, controller): super(HP8904Device, self).__init__(idn, address, controller) - + deviceRegister.register_manager(HP8904Device) diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/__init__.py --- 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 """ diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/detect.py --- /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() diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/gpib_utils.py --- 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.*) )?(?P\w+/\w+)( (?P.*))?') - + bool_re = re.compile( + r'((?P.*) )?(?P\w+/\w+)( (?P.*))?') + 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) diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/gpibcontroller.py --- 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 = "" + 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'+'|'.join(self._units)+')' + reunits = '(?P' + '|'.join(self._units) + ')' reexpr = r'(?P[-]?[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. - diff -r b55977dcc311 -r 96e30b092f70 pygpibtoolkit/tools.py --- 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: diff -r b55977dcc311 -r 96e30b092f70 setup.py --- /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', + ]} + )