Fri, 05 Sep 2008 00:25:19 +0200
Add an option to qgpib_plotter to make it auto display any newly received plot (+ fix in plot list management)
# 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 gpib: create serial connection to GPIB-USB device (Prologix is the only supported device for now). """ import serial from serial.serialutil import SerialException import time from pygpibtoolkit.tools import AbstractRegister import operator class ConnectionError(Exception): pass class Condition(object): def __call__(self, device): return True def __and__(self, cond): assert isinstance(cond, Condition) return _ComposedCondition(operator.__and__, self, cond) def __or__(self, cond): assert isinstance(cond, Condition) return _ComposedCondition(operator.__or__, self, cond) class _ComposedCondition(Condition): def __init__(self, op, *args): self._conditions = list(args[:]) self._reduc_op = op for cond in args: assert isinstance(cond, Condition) if isinstance(cond, _ComposedCondition) and cond._reduc_op == op: i = self._conditions.index(cond) self._conditions[i:i+1] = cond._conditions def __call__(self, device): return reduce(self._reduc_op, [f(device) for f in self._conditions]) class Constants(object): def __init__(self): self.constants = {} self.descriptions = {} self.rev_constants = {} for v, k, m in self._constants: self.k = v self.constants[v] = k self.rev_constants[k] = v self.descriptions[v] = m def __getitem__(self, k): if isinstance(k, basestring): return self.rev_constants[k] else: return self.constants[k] def get_description(self, k): if isinstance(k, basestring): k = self.rev_constants[k] return self.descriptions[k] class MODE(Constants): _constants = [(1, "CONTROLLER", "Set device as Controller in Charge"), (0, "DEVICE", "Set device as simple listener"), ] class ModeCommand(object): def __init__(self, description, name, condition=None): self.name = name self.description = description self.condition = condition class AbstractCommand(object): """ Base class for HPIB command descritption. This is actually a attribute descriptor, which should have AbstractGPIBDevice derived classes as owner. """ _readonly = True _init_value = None def __get__(self, instance, owner): if instance is None: return self return instance._get(self.__class__.__name__) def __set__(self, instance, value): if instance is None: return self return instance._set(self.__class__.__name__, value) def get_value_from_device(self, device): cmd = self.build_get_cmd() value = device.send_command(cmd) value = self.convert_from(value) return value def send_value_to_device(self, device, value): cmd, value = self.build_set_cmd(value) res = device.send_command(cmd) return res, self.convert_to(value) def build_get_cmd(self): return self.__class__.__name__ def build_set_cmd(self, *value): raise ValueError, "Can't set value for command '%s'"%self.__class__.__name__ def convert_from(self, *value): return None def convert_to(self, *value): return None #XXX TODO: remove this class Command(AbstractCommand): pass class AbstractValue(Command): _readonly = False def build_get_cmd(self): return self.__class__.__name__ + "?" def build_set_cmd(self, *value): value = self.convert_to(value) cmd = "%s %s"%(self.__class__.__name__, value) return cmd, value def convert_to(self, *value): if value: return str(value[0]) return "" def convert_from(self, *value): if value: return self._type(value[0].strip()) return None class BoolValue(AbstractValue): _type = bool def convert_from(self, *value): if value: return value[0] and value[0].lower() in ['1','true','yes','on'] return False def convert_to(self, *value): if value: return value[0] and "1" or "0" return "" # XXX is it correct? class IntValue(AbstractValue): _type = int def convert_from(self, *value): if value: # int is resturned as a string representing a float return self._type(float(value[0].strip())) return None class flag(int): def __new__(cls, val, constants): val = int.__new__(cls, val) val._constants = constants for v, name, desc in constants: if name not in ['', 'N/A']: setattr(val, name, v) return val def __str__(self): return '%s <' + '|'.join([x[1] for x in self._constants if x[0]&self]) + ">" def flags(self): 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']] 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): value = value[0].strip().split() if len(value)==1: freq = float(value) unit = self._units[0] elif len(value)==2: freq = float(value[0]) unit = value[1] else: raise ValueError, "Can't interpret %s as a %s"%(repr(value), self._name) else: freq = float(value[0]) unit = self._units[0] elif len(value)==2: freq = float(value[0]) 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 return "%s%s"%(freq, unit) return "" # XXX is it correct? class FrequencyValue(FloatUnitValue): _units = ['Hz','kHz','mHz',] _name = "frequency" class VoltageValue(FloatUnitValue): _units = ['V','mV',] _name = "voltage" class DurationValue(FloatUnitValue): _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 "''" class EnumValue(StringValue): _values = [] def convert_to(self, *value): if value: assert value[0] in self._values return "%s"%self._values.index(value[0]) return "" # XXX class Mode(AbstractValue): _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): # # IEEE 488.2 Status Byte constants # MAV = 0x10 # Message AVailable: bit 4 of the Status Byte # ESB = 0x20 # Event Status Bit: bit 5 of the Status Byte # MSS = 0x40 # Master Summary Status bit: bit 6 of the Status Byte (NOT # # sent in response to a serial poll) # RQS = 0x40 # Request Service: bit 6 of the Status Byte (when sent in # # response to a serial poll) # class SESR(Constants): # # SESR constants (Standard Event Status Register) # PON = 0x80 # Power On: Power has been turned On since last register # # read access # URQ = 0x40 # User Request: the user has activated some device control # # (whatever the Remote Local state is) # CME = 0x20 # Command Error # EXE = 0x10 # Execution Error # DDE = 0x08 # Device Dependant Error # QYE = 0x04 # QuerY Error (attempt to read data while Output Queue is # # empty, or data in the OQ was lost) # RQC = 0x02 # Request Control: tell the CiC that the device wants to # # become the CiC # 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.