diff --git a/exopy_qcircuits/instruments/drivers/ZI/UHFLI.py b/exopy_qcircuits/instruments/drivers/ZI/UHFLI.py index 00a1e22..90491a8 100644 --- a/exopy_qcircuits/instruments/drivers/ZI/UHFLI.py +++ b/exopy_qcircuits/instruments/drivers/ZI/UHFLI.py @@ -10,7 +10,7 @@ from __future__ import (division, unicode_literals, print_function, absolute_import) -from ..driver_tools import (InstrIOError, instrument_property, +from exopy_hqc_legacy.instruments.drivers.driver_tools import (InstrIOError, instrument_property, secure_communication) import sys from subprocess import call @@ -483,4 +483,4 @@ def get_DAQmodule(self, DAM, dimensions, signalID,signal_paths): # Stub class to remove make exopy happy class UHFLI: - pass \ No newline at end of file + pass diff --git a/exopy_qcircuits/instruments/drivers/ZI_tools.py b/exopy_qcircuits/instruments/drivers/ZI_tools.py index 6c3439d..1634e30 100644 --- a/exopy_qcircuits/instruments/drivers/ZI_tools.py +++ b/exopy_qcircuits/instruments/drivers/ZI_tools.py @@ -17,7 +17,7 @@ import sys, os -from .driver_tools import BaseInstrument, InstrIOError +from exopy_hqc_legacy.instruments.drivers.driver_tools import BaseInstrument, InstrIOError class ZIInstrument(BaseInstrument): diff --git a/exopy_qcircuits/instruments/drivers/dll/alazar935x.py b/exopy_qcircuits/instruments/drivers/dll/alazar935x.py index 70c06a8..66881d5 100644 --- a/exopy_qcircuits/instruments/drivers/dll/alazar935x.py +++ b/exopy_qcircuits/instruments/drivers/dll/alazar935x.py @@ -30,7 +30,7 @@ logger = logging.getLogger(__name__) -from ..dll_tools import DllInstrument +from exopy_hqc_legacy.instruments.drivers.dll_tools import DllInstrument try: from . import atsapi as ats diff --git a/exopy_qcircuits/instruments/drivers/dll/alazar935xMODIFSMARCOSAVE.py b/exopy_qcircuits/instruments/drivers/dll/alazar935xMODIFSMARCOSAVE.py index d00b579..ff191dd 100644 --- a/exopy_qcircuits/instruments/drivers/dll/alazar935xMODIFSMARCOSAVE.py +++ b/exopy_qcircuits/instruments/drivers/dll/alazar935xMODIFSMARCOSAVE.py @@ -30,7 +30,7 @@ import glob import re -from ..dll_tools import DllInstrument +from exopy_hqc_legacy.instruments.drivers.dll_tools import DllInstrument from . import atsapi as ats @@ -417,4 +417,4 @@ def get_demod(self, startaftertrig, duration, recordsPerCapture, mon_fichier.close() - return answerDemod, answerTrace \ No newline at end of file + return answerDemod, answerTrace diff --git a/exopy_qcircuits/instruments/drivers/dll/alazar935xTEMPSBUFFERTEMPSMISEENFORME.py b/exopy_qcircuits/instruments/drivers/dll/alazar935xTEMPSBUFFERTEMPSMISEENFORME.py index 7eded52..4acce2d 100644 --- a/exopy_qcircuits/instruments/drivers/dll/alazar935xTEMPSBUFFERTEMPSMISEENFORME.py +++ b/exopy_qcircuits/instruments/drivers/dll/alazar935xTEMPSBUFFERTEMPSMISEENFORME.py @@ -27,7 +27,7 @@ import math import time -from ..dll_tools import DllInstrument +from exopy_hqc_legacy.instruments.drivers.dll_tools import DllInstrument from . import atsapi as ats @@ -467,4 +467,4 @@ def get_demod(self, startaftertrig, duration, recordsPerCapture, else: answerTrace[Tracestring][:,:samplesPerDemod[i]] = data[i] - return answerDemod, answerTrace \ No newline at end of file + return answerDemod, answerTrace diff --git a/exopy_qcircuits/instruments/drivers/dll/labbrick.py b/exopy_qcircuits/instruments/drivers/dll/labbrick.py index 7747c60..5bfc285 100644 --- a/exopy_qcircuits/instruments/drivers/dll/labbrick.py +++ b/exopy_qcircuits/instruments/drivers/dll/labbrick.py @@ -16,9 +16,10 @@ To read the Dll of the LabBrick correctly, Visual C++ Studio 2013 is needed. """ -from ..driver_tools import (InstrIOError, secure_communication, - instrument_property) -from ..dll_tools import DllLibrary, DllInstrument +from exopy_hqc_legacy.instruments.drivers.driver_tools import (InstrIOError, + secure_communication, + instrument_property) +from exopy_hqc_legacy.instruments.drivers.dll_tools import DllLibrary, DllInstrument from inspect import cleandoc import ctypes diff --git a/exopy_qcircuits/instruments/drivers/dll_tools.py b/exopy_qcircuits/instruments/drivers/dll_tools.py deleted file mode 100644 index 3d487db..0000000 --- a/exopy_qcircuits/instruments/drivers/dll_tools.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -# ----------------------------------------------------------------------------- -# Copyright 2015-2016 by ExopyHqcLegacy Authors, see AUTHORS for more details. -# -# Distributed under the terms of the BSD license. -# -# The full license is in the file LICENCE, distributed with this software. -# ----------------------------------------------------------------------------- -"""Base classes for instrument relying on a custom dll for communication. - -""" -import ctypes -import time -from contextlib import contextmanager -from threading import Lock - -from .driver_tools import BaseInstrument, InstrIOError - - -class DllInstrument(BaseInstrument): - """ A base class for all instrumensts directly calling a dll. - - Attributes - ---------- - library : str - Name of the library to use to control this instrument. If is is - under the instruments/dll directory it will be automatically - found by the DllForm. - - """ - - library = '' - - -class DllLibrary(object): - """ Singleton class used to call a dll. - - This class should wrap in python all useful call to the dll, so that the - driver never need to access the _instance attribute. All manipulation of - the dll should be done inside the secure context for thread safety. - - Parameters - ---------- - path : unicode - Path to the dll library to load. - - type : {'windll', 'oledll'}, optional - Calling specification of the dll, by default the cdll one is used. - (This only makes sense under wind32) - - timeout : float, optional - Timeout to use when attempting to acquire the library lock. - - """ - - _instance = None - - def __new__(cls, *args, **kwargs): - if cls._instance is not None: - return cls._instance - else: - return super(DllLibrary, cls).__new__(cls) - - def __init__(self, path, **kwargs): - - if kwargs.get('type') == 'windll': - self.dll = ctypes.windll.LoadLibrary(path) - elif kwargs.get('type') == 'oledll': - self.dll = ctypes.windll.LoadLibrary(path) - else: - self.dll = ctypes.cdll.LoadLibrary(path) - - self.timeout = kwargs.get('timeout', 5.0) - - self.lock = Lock() - - @contextmanager - def secure(self): - """ Lock acquire and release method. - - """ - t = 0 - while not self.lock.acquire(): - time.sleep(0.1) - t += 0.1 - if t > self.timeout: - raise InstrIOError('Timeout in trying to acquire dll lock.') - try: - yield - finally: - self.lock.release() diff --git a/exopy_qcircuits/instruments/drivers/driver_tools.py b/exopy_qcircuits/instruments/drivers/driver_tools.py deleted file mode 100644 index 2d429eb..0000000 --- a/exopy_qcircuits/instruments/drivers/driver_tools.py +++ /dev/null @@ -1,299 +0,0 @@ -# -*- coding: utf-8 -*- -# ----------------------------------------------------------------------------- -# Copyright 2015-2016 by ExopyHqcLegacy Authors, see AUTHORS for more details. -# -# Distributed under the terms of the BSD license. -# -# The full license is in the file LICENCE, distributed with this software. -# ----------------------------------------------------------------------------- -""" -This module defines base tools for writing instrument drivers. - -All instruments drivers must inherit from `BaseInstrument` which ensure they -can use instrument properties (see below). Drivers should not directly subclass -`BaseInstrument` but one of it subclass implementing a connection protocol -(defining a kind of driver). For the time being the only supported protocol use -the VISA library. - -:Contains: - InstrError : - General exception for instrument error. - InstrIOError : - General exception for instrument communication error. - BaseInstrument : - Base class for all drivers. - instrument_properties : - subclass of property allowing to cache a property on certain condition, - and to reset the cache. - secure_communication : - decorator making sure that a communication error cannot simply be - resolved by attempting again to send a message. - -""" -import inspect -from inspect import cleandoc -from textwrap import fill -from functools import wraps - -from exopy.utils.traceback import format_exc - - -class InstrError(Exception): - """Generic error raised when an instrument does not behave as expected - """ - pass - - -class InstrIOError(InstrError): - """Generic error raised when an instrument does not behave as expected - """ - pass - - -class instrument_property(property): - """Property allowing to cache the result of a get operation and return it - on the next get. The cache can be cleared. - - """ - - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - super(instrument_property, self).__init__(fget, fset, fdel, doc) - if fget is not None: - self.name = fget.__name__ - elif fset is not None: - self.name = fset.__name__ - else: - err = 'Need either a setter or getter for an instrument_property.' - raise ValueError(err) - - self.type = None - self.valid_values = [] - - def __get__(self, obj, objtype=None): - """ - """ - if obj is not None: - name = self.name - if name in obj._caching_permissions: - try: - return obj._cache[name] - except KeyError: - aux = super(instrument_property, self).__get__(obj, - objtype) - obj._cache[name] = aux - return aux - else: - return super(instrument_property, self).__get__(obj, objtype) - - else: - return self - - def __set__(self, obj, value): - """ - """ - name = self.name - if name in obj._caching_permissions: - try: - if obj._cache[name] == value: - return - except KeyError: - pass - super(instrument_property, self).__set__(obj, value) - obj._cache[name] = value - else: - super(instrument_property, self).__set__(obj, value) - - -def secure_communication(max_iter=2): - """Decorator making sure that a communication error cannot simply be - resolved by attempting again to send a message. - - Parameters - ---------- - max_iter : int, optionnal - Maximum number of attempt to perform before propagating the exception - - """ - def decorator(method): - - @wraps(method) - def wrapper(self, *args, **kwargs): - - i = 0 - # Try at most `max_iter` times to excute method - while i < max_iter + 1: - try: - return method(self, *args, **kwargs) - - # Catch all the exception specified by the driver - except self.secure_com_except: - if i == max_iter: - raise - else: - print(format_exc()) - self.reopen_connection() - i += 1 - - wrapper.__wrapped__ = method - return wrapper - - return decorator - - -class BaseInstrument(object): - """Base class for all drivers - - This class set up the caching mechanism and its management in terms of - permissions and cleaning of the caches. - - Parameters - ---------- - connection_info : dict - Dict containing all the necessary information to open a connection to - the instrument - caching_allowed : bool, optionnal - Boolean use to determine if instrument properties can be cached - caching_permissions : dict(str : bool), optionnal - Dict specifying which instrument properties can be cached, override the - default parameters specified in the class attribute. - - Attributes - ---------- - caching_permissions : dict(str : bool) - Dict specifying which instrument properties can be cached. - secure_com_except : tuple(Exception) - Tuple of the exceptions to be catched by the `secure_communication` - decorator - owner : str - Identifier of the last owner of the driver. Used to know whether or not - previous settings might heve been modified by other parts of the - program. - - Methods - ------- - open_connection() : virtual - Open the connection to the instrument - close_connection() : virtual - Close the connection with the instrument - reopen_connection() : virtual - Reopen the connection with the instrument with the same parameters as - previously - check_connection() : virtual - Check whether or not the cache is likely to have been corrupted - clear_cache(properties = None) - Clear the cache of some or all instrument properties - - """ - caching_permissions = {} - secure_com_except = (InstrIOError) - owner = '' - - def __init__(self, connection_info, caching_allowed=True, - caching_permissions={}, auto_open=True): - super(BaseInstrument, self).__init__() - if caching_allowed: - # Avoid overriding class attribute - perms = self.caching_permissions.copy() - perms.update(caching_permissions) - self._caching_permissions = set([key for key in perms - if perms[key]]) - else: - self._caching_permissions = set([]) - self._cache = {} - - def open_connection(self): - """Open a connection to an instrument - """ - message = fill(cleandoc( - '''This method is used to open the connection with the - instrument and should be implemented by classes - subclassing BaseInstrument'''), - 80) - raise NotImplementedError(message) - - def close_connection(self): - """Close the connection established previously using `open_connection` - """ - message = fill(cleandoc( - '''This method is used to close the connection with the - instrument and should be implemented by classes - subclassing BaseInstrument'''), - 80) - raise NotImplementedError(message) - - def reopen_connection(self): - """Reopen the connection established previously using `open_connection` - """ - message = fill(cleandoc( - '''This method is used to reopen a connection whose state - is suspect, for example the last message sent did not - go through.'''), - 80) - raise NotImplementedError(message) - - def check_connection(self): - """Check whether or not the cache is likely to have been corrupted. - - """ - message = fill(cleandoc( - '''This method is used to check that the instrument is - in remote mode and that none of the values in the cache - has been corrupted by a local user.'''), - 80) - raise NotImplementedError(message) - - def connected(self): - """Return whether or not commands can be sent to the instrument - """ - message = fill(cleandoc( - '''This method returns whether or not command can be - sent to the instrument'''), - 80) - raise NotImplementedError(message) - - def clear_cache(self, properties=None): - """ Clear the cache of all the properties or only the one of specified - ones. - - Parameters - ---------- - properties : iterable of str, optionnal - Name of the properties whose cache should be cleared. All caches - will be cleared if not specified. - - """ - test = lambda obj: isinstance(obj, instrument_property) - cache = self._cache - if properties: - for name, instr_prop in inspect.getmembers(self.__class__, test): - if name in properties and name in cache: - del cache[name] - else: - self._cache = {} - - def check_cache(self, properties=None): - """Return the value of the cache of the instruments - - Parameters - ---------- - properties : iterable of str, optionnal - Name of the properties whose cache should be cleared. All caches - will be cleared if not specified. - - Returns - ------- - cache : dict - Dict containing the cached value, if the properties arg is given - None will be returned for the field with no cached value. - - """ - test = lambda obj: isinstance(obj, instrument_property) - cache = {} - if properties: - for name, instr_prop in inspect.getmembers(self.__class__, test): - if name in properties: - cache[name] = self._cache.get(name) - else: - cache = self._cache.copy() - - return cache diff --git a/exopy_qcircuits/instruments/drivers/visa/keysight_ena.py b/exopy_qcircuits/instruments/drivers/visa/keysight_ena.py index c5ff1ea..4cc2891 100644 --- a/exopy_qcircuits/instruments/drivers/visa/keysight_ena.py +++ b/exopy_qcircuits/instruments/drivers/visa/keysight_ena.py @@ -21,9 +21,12 @@ single = 1 double = 3 -from ..driver_tools import (BaseInstrument, InstrIOError, InstrError, - secure_communication, instrument_property) -from ..visa_tools import VisaInstrument +from exopy_hqc_legacy.instruments.drivers.driver_tools import (BaseInstrument, + InstrIOError, + InstrError, + secure_communication, + instrument_property) +from exopy_hqc_legacy.instruments.drivers.visa_tools import VisaInstrument FORMATTING_DICT = {'PHAS': lambda x: np.angle(x, deg=True), diff --git a/exopy_qcircuits/instruments/drivers/visa/rohde_and_schwarz_psa.py b/exopy_qcircuits/instruments/drivers/visa/rohde_and_schwarz_psa.py index b128d87..fb068bf 100644 --- a/exopy_qcircuits/instruments/drivers/visa/rohde_and_schwarz_psa.py +++ b/exopy_qcircuits/instruments/drivers/visa/rohde_and_schwarz_psa.py @@ -22,9 +22,10 @@ single = 1 double = 3 -from ..driver_tools import (InstrIOError, secure_communication, - instrument_property) -from ..visa_tools import VisaInstrument +from exopy_hqc_legacy.instruments.drivers.driver_tools import (InstrIOError, + secure_communication, + instrument_property) +from exopy_hqc_legacy.instruments.drivers.visa_tools import VisaInstrument FORMATTING_DICT = {'PHAS': lambda x: np.angle(x, deg=True), @@ -171,4 +172,4 @@ def get_single_freq(self,freq,reflevel,rbw,vbw,avrg_num): 'SENSe:LIST:POW? {},{},0,OFF,NORM,{},{},500us,0;*OPC'. format(freq,reflevel,rbw,vbw)))) - return 10*np.log10(np.average(10**(np.array(values)/10))) \ No newline at end of file + return 10*np.log10(np.average(10**(np.array(values)/10))) diff --git a/exopy_qcircuits/instruments/drivers/visa/tabor_awg.py b/exopy_qcircuits/instruments/drivers/visa/tabor_awg.py index cdc19a0..ca24223 100644 --- a/exopy_qcircuits/instruments/drivers/visa/tabor_awg.py +++ b/exopy_qcircuits/instruments/drivers/visa/tabor_awg.py @@ -16,9 +16,11 @@ """ from threading import Lock from contextlib import contextmanager -from ..driver_tools import (BaseInstrument, InstrIOError, secure_communication, - instrument_property) -from ..visa_tools import VisaInstrument +from exopy_hqc_legacy.instruments.drivers.driver_tools import (BaseInstrument, + InstrIOError, + secure_communication, + instrument_property) +from exopy_hqc_legacy.instruments.drivers.visa_tools import VisaInstrument from visa import VisaTypeError from textwrap import fill from inspect import cleandoc @@ -470,4 +472,4 @@ def set_DC_offset(self,channel,value): Allowed range: {} to {} V.'''.format(DC_min,DC_max))) else: raise InstrIOError(cleandoc('''Channel number out of range. - Accepted channel numbers: {}.'''.format(channels))) \ No newline at end of file + Accepted channel numbers: {}.'''.format(channels))) diff --git a/exopy_qcircuits/instruments/drivers/visa_tools.py b/exopy_qcircuits/instruments/drivers/visa_tools.py deleted file mode 100644 index 8f67792..0000000 --- a/exopy_qcircuits/instruments/drivers/visa_tools.py +++ /dev/null @@ -1,240 +0,0 @@ -# -*- coding: utf-8 -*- -# ----------------------------------------------------------------------------- -# Copyright 2015-2016 by ExopyHqcLegacy Authors, see AUTHORS for more details. -# -# Distributed under the terms of the BSD license. -# -# The full license is in the file LICENCE, distributed with this software. -# ----------------------------------------------------------------------------- -"""Base classes for instrument relying on the VISA protocol. - -""" -try: - from pyvisa.highlevel import ResourceManager - from pyvisa import errors -except ImportError as e: - msg = 'The PyVISA library is necessary to use the visa backend.' - raise ImportError(msg) from e - -from .driver_tools import BaseInstrument, InstrIOError - - -class VisaInstrument(BaseInstrument): - """Base class for drivers using the VISA library to communicate - - This class uses the PyVisa binder to the VISA library to open a - communication. The PyVisa object (Instrument instance) is cached and this - class provides conveninence methods to call all its method and propeties - to set its attributes. The connection to the instrument is opened upon - initialisation. - - Parameters - ---------- - connection_info : dict - Dict containing all the necessary information to open a connection to - the instrument - caching_allowed : bool, optionnal - Boolean use to determine if instrument properties can be cached - caching_permissions : dict(str : bool), optionnal - Dict specifying which instrument properties can be cached, override the - default parameters specified in the class attribute. - - Attributes - ---------- - caching_permissions : dict(str : bool) - Dict specifying which instrument properties can be cached. - secure_com_except : tuple(Exception) - Tuple of the exceptions to be catched by the `secure_communication` - decorator - connection_str : VISA string uses to open the communication - - The following attributes simply reflects the attribute of a `PyVisa` - `Instrument` object : - timeout - write_termination - read_termination - delay - - Methods - ------- - open_connection() : - Open the connection to the instrument using the `connection_str` - close_connection() : - Close the connection with the instrument - reopen_connection() : - Reopen the connection with the instrument with the same parameters as - previously - check_connection() : virtual - Check whether or not the cache is likely to have been corrupted - - The following method simply call the PyVisa method of the driver - write(mess) - read() - read_values() - ask(mess) - ask_for_values() - clear() - trigger() - read_raw() - - """ - secure_com_except = (InstrIOError, errors.VisaIOError) - - def __init__(self, connection_info, caching_allowed=True, - caching_permissions={}, auto_open=True): - super(VisaInstrument, self).__init__(connection_info, caching_allowed, - caching_permissions) - self.connection_str = connection_info['resource_name'] - - self._driver = None - if auto_open: - self.open_connection() - - def open_connection(self, **para): - """Open the connection to the instr using the `connection_str`. - - """ - rm = ResourceManager() - try: - self._driver = rm.open_resource(self.connection_str, **para) - except errors.VisaIOError as er: - self._driver = None - raise InstrIOError(str(er)) - - def close_connection(self): - """Close the connection to the instr. - - """ - if self._driver: - self._driver.close() - self._driver = None - return True - - def reopen_connection(self): - """Reopen the connection with the instrument with the same parameters - as previously. - - """ - para = {'timeout': self._driver.timeout, - 'query_delay': self._driver.query_delay, - 'write_termination': self._driver.write_termination, - 'read_termination': self._driver.read_termination, - } - self._driver.close() - self.open_connection(**para) - - def connected(self): - """Returns whether commands can be sent to the instrument - """ - return bool(self._driver) - - def write(self, message): - """Send the specified message to the instrument. - - Simply call the `write` method of the `Instrument` object stored in - the attribute `_driver` - """ - self._driver.write(message) - - def read(self): - """Read one line of the instrument's buffer. - - Simply call the `read` method of the `Instrument` object stored in - the attribute `_driver` - """ - return self._driver.read() - - def read_values(self, format=0): - """Read one line of the instrument's buffer and convert to values. - - Simply call the `read_values` method of the `Instrument` object - stored in the attribute `_driver` - """ - return self._driver.read_values(format=0) - - def ask(self, message): - """Send the specified message to the instrument and read its answer. - - Simply call the `ask` method of the `Instrument` object stored in - the attribute `_driver` - """ - return self._driver.query(message) - - def ask_for_values(self, message, format=2): - """Send the specified message to the instrument and convert its answer - to values. - - By default assume the values are returned as ascii. - - Simply call the `ask_for_values` method of the `Instrument` object - stored in the attribute `_driver` - - """ - return self._driver.ask_for_values(message, format) - - def clear(self): - """Resets the device (highly bus dependent). - - Simply call the `clear` method of the `Instrument` object stored in - the attribute `_driver` - """ - return self._driver.clear() - - def trigger(self): - """Send a trigger to the instrument. - - Simply call the `trigger` method of the `Instrument` object stored - in the attribute `_driver` - """ - return self._driver.assert_trigger() - - def read_raw(self): - """Read one line of the instrument buffer and return without stripping - termination caracters. - - Simply call the `read_raw` method of the `Instrument` object stored - in the attribute `_driver` - """ - return self._driver.read_raw() - - def _timeout(self): - return self._driver.timeout - - def _set_timeout(self, value): - self._driver.timeout = value - - timeout = property(_timeout, _set_timeout) - """Conveninence to set/get the `timeout` attribute of the `Instrument` - object""" - - def _delay(self): - return self._driver.query_delay - - def _set_delay(self, value): - self._driver.query_delay = value - - delay = property(_delay, _set_delay) - """Conveninence to set/get the `query_delay` attribute of the `Instrument` - object""" - - def _write_termination(self): - return self._driver.write_termination - - def _set_write_termination(self, value): - self._driver.write_termination = value - - write_termination = property(_write_termination, - _set_write_termination) - """Conveninence to set/get the `write_termination` attribute of the - `Instrument` object""" - - def _read_termination(self): - return self._driver.read_termination - - def _set_read_termination(self, value): - self._driver.read_termination = value - - read_termination = property(_read_termination, - _set_read_termination) - """Conveninence to set/get the `read_termination` attribute of the - `Instrument` object""" \ No newline at end of file diff --git a/exopy_qcircuits/tasks/tasks/instr/AWG_tasks.py b/exopy_qcircuits/tasks/tasks/instr/AWG_tasks.py index 7765349..ce39ad8 100644 --- a/exopy_qcircuits/tasks/tasks/instr/AWG_tasks.py +++ b/exopy_qcircuits/tasks/tasks/instr/AWG_tasks.py @@ -19,7 +19,7 @@ from atom.api import (Str,Enum,Typed) from exopy.utils.atom_util import ordered_dict_from_pref, ordered_dict_to_pref from collections import OrderedDict -from exopy_qcircuits.instruments.drivers.visa_tools import InstrIOError +from exopy_hqc_legacy.instruments.drivers.visa_tools import InstrIOError class AWGSetDCOffsetTask(InstrumentTask):