Wed, 18 Mar 2009 00:26:27 +0100
many improvements:
- in gpibcontroler system (it begins to work fine),
- add HP3456A description module,
- add an almost empty HP8904A description module,
- add forgotten files (tests, mockups)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/3456logger.py Wed Mar 18 00:26:27 2009 +0100 @@ -0,0 +1,45 @@ +#!/usr/bin/python +import sys +import os +import signal +import time +import optparse + +try: + from pygpibtoolkit.gpibcontroller import GPIBController, deviceRegister +except ImportError: + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) + from pygpibtoolkit.gpibcontroller import GPIBController, deviceRegister + +import pygpibtoolkit.HP3562A +import pygpibtoolkit.HP3456 + +from pygpibtoolkit.prologix import GPIB + +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) + + +cnx = GPIB(device=options.device) +c = GPIBController(cnx) + +m = c.register_device(24, "HP3456A") + +def cb(val): + print val + +m.register_data_cb(cb) +m.send_command('SM004') +m.send_command('T1SO1') + +try: + while True: + time.sleep(0.1) +except KeyboardInterrupt: + pass + +m.send_command('SO0') +c.stop()
--- a/bin/gpib_detect Fri Sep 05 00:25:19 2008 +0200 +++ b/bin/gpib_detect Wed Mar 18 00:26:27 2009 +0100 @@ -10,7 +10,7 @@ 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") @@ -20,7 +20,9 @@ options, argv = opt.parse_args(sys.argv) print "Detecting GPIB devices on the bus. Please wait until completion." - c = GPIBController(device=options.device) + cnx = GPIB(device=options.device) + c = GPIBController(cnx) + signal.signal(signal.SIGINT, c.stop) signal.signal(signal.SIGQUIT, c.stop) @@ -31,7 +33,7 @@ print "GPIB devices:" for k in sorted(devices.keys()): print "%-3d: %s"%(k, devices[k]) - + return c, devices if __name__ == "__main__": - main() + c, dev = main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/HP3456.py Wed Mar 18 00:26:27 2009 +0100 @@ -0,0 +1,238 @@ +# -*- coding: utf-8 -*- +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" Copyright (c) 2007-2009 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr + +""" +import mx.DateTime as dt + +from pygpibtoolkit.pygpib import Constants, Command +from pygpibtoolkit.pygpib import Mode, ModeCommand +from pygpibtoolkit.pygpib import WriteOnlyMode +from pygpibtoolkit.pygpib import BoolValue, FloatValue +from pygpibtoolkit.gpibcontroller import AbstractGPIBDevice, deviceRegister + + +class Function(WriteOnlyMode): + "Function" + _init_value = "S0F1" + + #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") + S0F4 = ModeCommand("2 wire Ohm", "OHM2") + S0F5 = ModeCommand("4 wire Ohm", "OHM4") + + S1F1 = ModeCommand("DC/DC Voltage Ratio", "DCV/DCV") + S1F2 = ModeCommand("AC/DC Voltage Ratio", "ACV/DCV") + 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") + R4 = ModeCommand("10", "10") + R5 = ModeCommand("100", "100") + R6 = ModeCommand("1E3", "1E3") + R7 = ModeCommand("10E3", "10E3") + 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" + + M0 = ModeCommand("Off", "OFF") + M1 = ModeCommand("Pass/Fail", "P/F") + M2 = ModeCommand("Statistics", "STAT") + M3 = ModeCommand("Null", "NULL") + M4 = ModeCommand("dBm", "DBM") + M5 = ModeCommand(u"Thermistor (°F)", "TH_F") + M6 = ModeCommand(u"Thermistor (°C)", "TH_C") + M7 = ModeCommand("Scale", "") + M8 = ModeCommand("% Error", "") + M9 = ModeCommand("dB", "") + +class AutoZero(WriteOnlyMode): + "Auto Zero" + _init_value = "Z1" + + Z0 = ModeCommand("Off", "OFF") + Z1 = ModeCommand("On", "ON") + +class Filter(WriteOnlyMode): + "Filter" + _init_value = "FL0" + + FL0 = ModeCommand("Off", "OFF") + FL1 = ModeCommand("On", "ON") + +class Test(WriteOnlyMode): + "Test" + _init_value = "TE0" + + 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" + + SO0 = ModeCommand("Off", "OFF") + SO1 = ModeCommand("On", "ON") + +class Display(WriteOnlyMode): + "Display" + _init_value = "D1" + + D0 = ModeCommand("Off", "OFF") + D1 = ModeCommand("On", "ON") + +class OutputFormat(WriteOnlyMode): + "Output Format" + _init_value = "P0" + + 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 "?" + +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__ + + def build_set_cmd(self, *value): + value = self.convert_to(*value) + 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 + + def __init__(self, idn, address, controller): + super(HP3456Device, self).__init__(idn, address, controller) + self.reset_measures() + self._data_cb = None + + def manage_srq(self, 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) + + def data_cb(self, data): + if data: + try: + data = float(data) + self.measures.append((dt.now(), data)) + if self._data_cb: + self._data_cb(self.measures[-1]) + except: + pass + + def reset_measures(self): + self.measures = [] + + def register_data_cb(self, cb): + self._data_cb = cb + + +deviceRegister.register_manager(HP3456Device)
--- a/pygpibtoolkit/HP3562A/HP356X.py Fri Sep 05 00:25:19 2008 +0200 +++ b/pygpibtoolkit/HP3562A/HP356X.py Wed Mar 18 00:26:27 2009 +0100 @@ -344,7 +344,7 @@ "SACR - Send Auto Carrier" class HP356XDevice(AbstractGPIBDevice): - _accepts = ["HP3562A", "HP3563A"] + _accepts = [ r"^(?P<model>HP *356[23][ABCD]).*$",] _idn = "ID?" def manage_srq(self, statusbyte): print "Managing SRQ", statusbyte
--- a/pygpibtoolkit/HP3562A/q3562A.py Fri Sep 05 00:25:19 2008 +0200 +++ b/pygpibtoolkit/HP3562A/q3562A.py Wed Mar 18 00:26:27 2009 +0100 @@ -22,10 +22,8 @@ from PyQt4 import QtGui, QtCore, uic from PyQt4.QtCore import SIGNAL, Qt -if "-m" in sys.argv: - from dump_datablock_mockup import HP3562dumper -else: - from dump_datablock import HP3562dumper +# WARNING, may be "replaced" by mockup +from dump_datablock import HP3562dumper from pygpibtoolkit.qt4.qpreferences import BaseItem, IntItem, UnicodeItem, ColorItem from pygpibtoolkit.qt4.qpreferences import PointItem, SizeItem, ByteArrayItem @@ -481,6 +479,11 @@ options, argv = opt.parse_args(sys.argv) + if options.mockup: + # overwrite "normal" module + global HP3562dumper + from dump_datablock_mockup import HP3562dumper + a = QtGui.QApplication(argv) w = Qt3562() files = [f for f in argv[1:] if os.path.isfile(f)]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/HP3562A/test/test_HP3562A.py Wed Mar 18 00:26:27 2009 +0100 @@ -0,0 +1,11 @@ +# +from logilab.common.testlib import TestCase, InnerTest, unittest_main + +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() == {})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/HP8904.py Wed Mar 18 00:26:27 2009 +0100 @@ -0,0 +1,34 @@ +# 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-2009 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr + +""" +import mx.DateTime as dt + +from pygpibtoolkit.pygpib import Constants, Command +from pygpibtoolkit.pygpib import Mode, ModeCommand +from pygpibtoolkit.pygpib import WriteOnlyMode +from pygpibtoolkit.gpibcontroller import AbstractGPIBDevice, deviceRegister + + + +class HP8904Device(AbstractGPIBDevice): + _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/gpibcontroller.py Fri Sep 05 00:25:19 2008 +0200 +++ b/pygpibtoolkit/gpibcontroller.py Wed Mar 18 00:26:27 2009 +0100 @@ -20,6 +20,7 @@ import sys import threading import time +import re from inspect import isclass from serial.serialutil import SerialException @@ -40,7 +41,17 @@ if not pname.startswith('_') and isclass(param) and \ issubclass(param, AbstractCommand) and \ param.__module__ == modname: - setattr(new_cls, pname, param()) + p = param() + 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): @@ -49,7 +60,12 @@ @classmethod def accepts(cls, idn): - return idn in cls._accepts + for regex in cls._accepts: + m = re.match(regex, idn) + if m: + return m.group('model') + return False + #return idn in cls._accepts def __init__(self, idn, address, controller): self._idn = idn @@ -59,8 +75,9 @@ self._cache = {} for pname, param in self.__class__.__dict__.items(): - if isinstance(param, AbstractCommand) and not param._readonly: + 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 @@ -88,20 +105,34 @@ pass def send_command(self, cmd): - return self._controller.send_command(self._address, cmd).strip() + ret = self._controller.send_command(self._address, cmd) + if ret: + ret = ret.strip() + return ret + + def read_data(self): + """ + Read currently available DATA in buffer + """ + return self.send_command('') + class GPIBDeviceRegister(object): def __init__(self): self._registry = [] + def register_manager(self, mgr): self._registry.append(mgr) + def get_manager(self, idn): for mgr in self._registry: if mgr.accepts(idn): return mgr return None + def get_idn_cmds(self): - return [mgr._idn for mgr in self._registry] + return [mgr._idn for mgr in self._registry if mgr._idn] + def __str__(self): msg = "<GPIBDeviceRegister: %s managers\n"%len(self._registry) for mgr in self._registry: @@ -133,15 +164,13 @@ ready.) """ - def __init__(self, device="/dev/ttyUSB0", controller_address=21): + def __init__(self, gpibcnx=None, controller_address=21): self._address = controller_address - try: - self._cnx = GPIB(device) - except SerialException: - self._cnx = None + self._cnx = gpibcnx self._devices = {} + self._debug = False self._setup_threading_system() - + def __del__(self): print "deleting controller" self._stop.set() @@ -158,6 +187,7 @@ self._cnx_thread = threading.Thread(name="GPIBConnectionThread", target=self._cnx_loop) self._cnx_thread.start() + self._suspended = False self._loop_interrupter.set() def _check_srq(self): @@ -166,18 +196,20 @@ 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: - #sys.stderr.write('.') + if self._debug: + sys.stderr.write('.') if self._stop.isSet(): print "_stop set, exiting" return while not self._loop_interrupter.isSet(): - #sys.stderr.write('|') + if self._debug: + sys.stderr.write('|') self._loop_interrupter.wait() self._loop_interrupter.clear() # first we check for SRQ and dispatch its management @@ -213,10 +245,29 @@ def stop(self, *args): self._stop.set() + + def suspend(self, *args): + while not self._loop_interrupter.isSet(): + self._loop_interrupter.wait() + 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" + self._suspended = False + self._loop_interrupter.set() def send_command(self, addr, cmd, sync=True, cb=None): + #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 + self._n_cmds_lock.acquire() self._n_cmds += 1 n_cmd = self._n_cmds @@ -238,7 +289,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 @@ -258,6 +309,7 @@ if idn: self.register_device(address, idn) devices[address] = str(idn) + print "registered device", idn break else: # redo a spoll, it should have set the err bit @@ -304,4 +356,11 @@ finally: self._loop_interrupter.set() - + def get_devicemanager(self, address): + return self._devices.get(address) + + def __getitem__(self, address): + return self._devices.get(address) + + def keys(self): + return self._devices.keys()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/gpibmockup.py Wed Mar 18 00:26:27 2009 +0100 @@ -0,0 +1,170 @@ +# 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-2008 David Douard (Paris, FRANCE). +http://www.logilab.org/project/pygpibtoolkit -- mailto:david.douard@logilab.fr + +Module defining a mockup GPIB communication object. + +""" + +class BaseMockup(object): + _idnstr = "BaseMockup" + _idncmd = "*IDN?" + + _cmds = {} + + def __init__(self): + #self._current_cmd = None + self._current_data = None + + def cmd(self, cmd, *args): + if cmd == self._idncmd: + return self._idnstr + try: + if ' ' in cmd: + cmd, cmdargs = cmd.split(None, 1) + args = args + (cmdargs,) + _cmd = getattr(self, cmd) + self._current_data = _cmd(*args) + except AttributeError: + if cmd in self._cmds: + self._current_data = iter(self._cmds[cmd]) + else: + raise ValueError('Unknown command %s'%repr(cmd)) + else: + if isinstance(self._current_data, basestring): + ret = self._current_data + self._current_data = None + return ret + elif self._current_data is None: + return None + else: + try: + return self._current_data.next() + except StopIteration: + self._current_data = None + return None + return None + + def read(self): + try: + return self._current_data.next() + except StopIteration: + self._current_data = None + return None + except: + return None + +GPIB_CONTROLLER = 1 +GPIB_DEVICE = 0 + +class GPIB(object): + _retries = 15 + def __init__(self, address=0, mode=1, **kw): + """ + Create a new mockup GPIB controller. + """ + self.set_mode(mode) + self.set_address(address) + self._devices = {} + + def adddevice(self, add, mockup): + self._devices[add] = mockup + + 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, + + - if the device is in GPIB_DEVICE mode, this is its address. + """ + self._address = address + + 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 + + - GPIB_DEVICE: set the device as a standard GPIB device on the + bus. + """ + self._mode = mode + + def set_controller(self): + """ + Set GPIB device the Controller In Charge on the GPIB bus. + """ + self.set_mode(1) + + def set_device(self): + """ + Set the GPIB device as a simple device on the GPIB bus. + """ + self.set_mode(0) + + def send_command(self, cmd, address=None): + """ + Send the specified GPIB command on the bus (must be the CIC), + and read the answer. + Eventually, set the addressed device first. + """ + assert self._mode == 1 + if address is not None: + self.set_address(address) + + if self._address in self._devices: + return self._devices[self._address].cmd(cmd) + return None + + 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) + if self._address in self._devices: + return "".join(self._devices[self._address].read()) + ret = "" + return ret + + def check_srq(self): + """ + Check the SRQ line + """ + assert self._mode == 1, "must be the Controller In Charge" + return None + + def poll(self, addresses=None): + """ + Poll every address, and return a dictionnary + {add: status, ...} + """ + assert self._mode == 1, "must be the Controller In Charge" + ret = {} + if addresses is None: + for add, mock in self._devices.items(): + ret[add] = mock._idnstr + return ret + return {} + + def reset(self): + """ + Perform a reset of the USB device + + """ + pass +
--- a/pygpibtoolkit/prologix.py Fri Sep 05 00:25:19 2008 +0200 +++ b/pygpibtoolkit/prologix.py Wed Mar 18 00:26:27 2009 +0100 @@ -19,6 +19,7 @@ Module defining a communication object to talk to Prologix USB-GPIB controler. """ +import sys import serial import time @@ -31,7 +32,7 @@ class GPIB(object): _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'. @@ -108,7 +109,7 @@ Read the HPIB buffer from device, till EOI is performed, or timeout. """ if address is not None: - self.set_address(address) + self.set_address(address, check=False) self._cnx.write('++read eoi\r') # idem ret = "" i = 0 @@ -123,13 +124,24 @@ Check the SRQ line """ assert self._mode == 1, "must be the Controller In Charge" + ret = self._cnx.readline().strip() + if ret: + print "garbage:", ret self._cnx.write('++srq\r') ret = self._cnx.readline().strip() - if ret: + if ret in ["0","1"]: return bool(int(ret)) return None - def poll(self, addresses=None): + def trigger(self, address=None): + """ + Trigger device at 'address' + """ + if address is not None: + self.set_address(address, check=False) + self._cnx.write('++trg\r') # idem + + def poll(self, addresses=None, verbose=False): """ Poll every address, and return a dictionnary {add: status, ...} @@ -143,14 +155,25 @@ only_one = True if len(addresses)==0: return None - + + if verbose: + sys.stderr.write('polling ') dico = {} for add in addresses: self._cnx.write('++spoll %d\r'%add) + time.sleep(0.1) ret = self._cnx.readline().strip() if ret: + if verbose: + sys.stderr.write('X') dico[add] = int(ret) - time.sleep(0.3) # need to wait at least 150ms (not enough on prologix) + else: + if verbose: + sys.stderr.write('.') + + time.sleep(0.30) # need to wait at least 150ms (not enough on prologix) + if verbose: + sys.stderr.write('\n') self.set_address(self._address) if only_one and dico: return dico.values()[0]
--- a/pygpibtoolkit/pygpib.py Fri Sep 05 00:25:19 2008 +0200 +++ b/pygpibtoolkit/pygpib.py Wed Mar 18 00:26:27 2009 +0100 @@ -16,6 +16,7 @@ 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 @@ -82,13 +83,15 @@ class AbstractCommand(object): """ - Base class for HPIB command descritption. + Base class for HPIB command description. - This is actually a attribute descriptor, which should have + This is actually an attribute descriptor, which should have AbstractGPIBDevice derived classes as owner. """ _readonly = True _init_value = None + _cached = True + _cmds = [] def __get__(self, instance, owner): if instance is None: @@ -124,9 +127,10 @@ return None -#XXX TODO: remove this class Command(AbstractCommand): - pass + """pure command + """ + class AbstractValue(Command): _readonly = False @@ -135,7 +139,7 @@ return self.__class__.__name__ + "?" def build_set_cmd(self, *value): - value = self.convert_to(value) + value = self.convert_to(*value) cmd = "%s %s"%(self.__class__.__name__, value) return cmd, value @@ -209,14 +213,18 @@ if value: if len(value)==1: if isinstance(value[0], basestring): - value = value[0].strip().split() - if len(value)==1: + value = value[0].strip() + reunits = '(?P<unit>'+'|'.join(self._units)+')' + reexpr = r'(?P<value>[-]?[0-9]+([.][0-9]+)?) *' + reunits + m = re.match(reexpr, value) + try: + if m and m.group('unit'): + value = m.group('value') + unit = m.group('unit') + else: + unit = self._units[0] freq = float(value) - unit = self._units[0] - elif len(value)==2: - freq = float(value[0]) - unit = value[1] - else: + except Exception, e: raise ValueError, "Can't interpret %s as a %s"%(repr(value), self._name) else: freq = float(value[0]) @@ -226,7 +234,7 @@ unit = value[1] else: raise ValueError, "Can't interpret %s as a %s"%(repr(value), self._name) - assert unit.lower() in self._units, "Unit is not correct (%s)"%unit + assert unit in self._units, "Unit is not correct (%s)"%repr(unit) return "%s%s"%(freq, unit) return "" # XXX is it correct? @@ -257,34 +265,50 @@ return "%s"%self._values.index(value[0]) return "" # XXX -class Mode(AbstractValue): +class WriteOnlyMode(AbstractValue): + """ + A device mode which can only be wrote (there is no way for reading + the device mode), thus it must be kept in cache (and we must know + the init value mode (the subclass must have defined the + '_init_value' class attribute)). + """ + def __init__(self): + self._cmds = [] + for cmdname, cmd in self.__class__.__dict__.items(): + if isinstance(cmd, ModeCommand): + self._cmds.append(cmdname) + + 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 + instance._cache[self.__class__.__name__] = value + return getattr(instance, value) + + def __get__(self, instance, owner): + if instance is None: + return self + return instance._get(self.__class__.__name__) + + def build_set_cmd(self, value): + assert value in self._cmds + return value, value + +class Mode(WriteOnlyMode): _DATA_BLOCK = None _key = None - - def __init__(self): - self._cmds = [] - for cmdname, cmd in self.__dict__.items(): - if isinstance(cmd, ModeCommand): - self._cmds.append(cmdname) def get_mode(self, device): if self._key and self._DATA_BLOCK: mode = getattr(getattr(device, self._DATA_BLOCK), self._key) return mode return None - + def get_value_from_device(self, device): value = self.get_mode(device) return value - - def __get__(self, instance, owner): - if instance is None: - return self - return instance._get(self.__class__.__name__) - - def build_set_command(self, value): - assert value in self._cmds - return value # TODO # class STATUS_BYTE(Constants):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/test/mockupdevice.py Wed Mar 18 00:26:27 2009 +0100 @@ -0,0 +1,28 @@ +from pygpibtoolkit.pygpib import Constants, Command +from pygpibtoolkit.pygpib import Condition +from pygpibtoolkit.pygpib import BoolValue, IntValue, FloatValue +from pygpibtoolkit.pygpib import PercentageValue, FrequencyValue, DurationValue +from pygpibtoolkit.pygpib import VoltageValue +from pygpibtoolkit.pygpib import EnumValue, StringValue +from pygpibtoolkit.pygpib import Mode, ModeCommand, Flag + +from pygpibtoolkit.gpibcontroller import AbstractGPIBDevice, deviceRegister + +class CH(Mode): + A = ModeCommand("A trace","A") + B = ModeCommand("A trace","B") + + def get_mode(self, device): + return device.send_command('CH') + +class FR(FrequencyValue): + "FReq" + + +class SimpleMockupDevice(AbstractGPIBDevice): + _idn = "*IDN?" + _accepts = "Simple Mockup Device" + def manage_srq(self, statusbyte): + pass + +deviceRegister.register_manager(SimpleMockupDevice)