Repository: microsoft/Qcodes

Issue:
New updates to instruments break drivers 
Tested with AWG 520 and RohdeSchwarz_SGS100A driver (presumably others fail aswell, these are just the first 2 in my init). 

Problems come from the parameter IDN and the meta-data timeout. 

IDN is overwritten in some instruments (and overwriting should be possible in inherited instruments) and then complains upon initialization. 
The fix I propose is to have an overwrite=True option in the add_parameter in which overwriting does not cause an exception. 

The second problem is with timeout. This occurs because @alexcjohnson  has introduced it as a manual parameter for VISA instruments while the meta-data of @MerlinSmiles refers self._timeout. These two cause a conflict. (I need to look into it a bit deeper but this is my theory on this one). 

So to fix this 
- [x] IDN parameter -> Allow overwriting in inherited classes + implement fix in existing drivers 
- [x] new-name for timeout or better, make it a regular parameter always 



Discussion:
Did #194 not fix the IDN issue (at least for existing instruments)?

We also encountered the timeout issue. #201 fixes it (at least for our IVVI and Keithley driver)

> Did #194 not fix the IDN issue (at least for existing instruments)?

By looking at the code it should. What I did was switch branches to the master I would say I did this after #194 got merged but I'll test when I'm back in the lab. 

> We also encountered the timeout issue. #201 fixes it (at least for our IVVI and Keithley driver)

I think this should fix the second issue, have you tested it with snapshot? I would think the snapshot now contains two values for timeout (in the dictionary) that it overwrites with itself. I'd say it should work fine. 

I'll test both in the afternoon and give an update on wether they work. 

#201  solves the timeout issue, I propose we merge this ASAP. 

#194 does not solve the IDN issue completely, It does it in most cases but in the case of the IVVI (VISA instrument with some non-standard properties (e.g. no IDN command) It breaks down. 

I would propose an additional `overwrite=True` option in the add_parameter. This way the IDN can be overwritten in the special case of the IVVI. It can then return the data that is needed to construct the snapshot. 

Below I have posted the failure I get when initializing the IVVI. It relates to the get_dacs function relying on the use of snapshot, which is broken because it asks for IDN properties that don't work. 

@peendebak , You mentioned you have a working IVVI driver, are you using a different version than me or is it just the updating? 

@alexcjohnson I will now switch back to my old branch before these bugs where introduced. I would appreciate it a lot if you can look into this (it should not be too hard to fix) but I just don't have the time at the moment but would like to prevent diverging. 

Below: error trace for the IVVI driver 

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-539971eb4f9b> in <module>()
      7 
      8 # import as * puts all the imports and objects of the init in the global namespace
----> 9 from init.LaDucati import *

D:\GitHubRepos\PycQED_py3\init\LaDucati.py in <module>()
     75 AWG = tek.Tektronix_AWG5014(name='AWG', setup_folder=None,
     76                             address='TCPIP0::192.168.0.9', server_name=None)
---> 77 IVVI = iv.IVVI('IVVI', address='ASRL1', numdacs=16, server_name=None)
     78 Dux = qdux.QuTech_Duplexer('Dux', address='TCPIP0::192.168.0.101')
     79 

d:\githubrepos\qcodes\qcodes\instrument_drivers\QuTech\IVVI.py in __init__(self, name, address, reset, numdacs, dac_step, dac_delay, dac_max_delay, **kwargs)
     57 
     58         self.pol_num = np.zeros(self._numdacs)  # corresponds to POS polarity
---> 59         self.set_pol_dacrack('BIP', range(self._numdacs))
     60 
     61         # values based on descriptor

d:\githubrepos\qcodes\qcodes\instrument_drivers\QuTech\IVVI.py in set_pol_dacrack(self, flag, channels, getall)
    286 
    287         if getall:
--> 288             self.get_all()
    289 
    290     def get_pol_dac(self, channel):

d:\githubrepos\qcodes\qcodes\instrument_drivers\QuTech\IVVI.py in get_all(self)
    101 
    102     def get_all(self):
--> 103         return self.snapshot(update=True)
    104 
    105     def set_dacs_zero(self):

d:\githubrepos\qcodes\qcodes\utils\metadata.py in snapshot(self, update)
     17         '''
     18 
---> 19         snap = self.snapshot_base(update=update)
     20 
     21         if len(self.metadata):

d:\githubrepos\qcodes\qcodes\instrument\visa.py in snapshot_base(self, update)
    147 
    148     def snapshot_base(self, update=False):
--> 149         snap = super().snapshot_base(update=update)
    150 
    151         snap['address'] = self._address

d:\githubrepos\qcodes\qcodes\instrument\base.py in snapshot_base(self, update)
    370     def snapshot_base(self, update=False):
    371         snap = {'parameters': dict((name, param.snapshot(update=update))
--> 372                                    for name, param in self.parameters.items()),
    373                 'functions': dict((name, func.snapshot(update=update))
    374                                   for name, func in self.functions.items()),

d:\githubrepos\qcodes\qcodes\instrument\base.py in <genexpr>(.0)
    370     def snapshot_base(self, update=False):
    371         snap = {'parameters': dict((name, param.snapshot(update=update))
--> 372                                    for name, param in self.parameters.items()),
    373                 'functions': dict((name, func.snapshot(update=update))
    374                                   for name, func in self.functions.items()),

d:\githubrepos\qcodes\qcodes\utils\metadata.py in snapshot(self, update)
     17         '''
     18 
---> 19         snap = self.snapshot_base(update=update)
     20 
     21         if len(self.metadata):

d:\githubrepos\qcodes\qcodes\instrument\parameter.py in snapshot_base(self, update)
    255 
    256         if self.has_get and self._snapshot_get and update:
--> 257             self.get()
    258 
    259         state = self._latest()

d:\githubrepos\qcodes\qcodes\instrument\parameter.py in get(self)
    435             e.args = e.args + (
    436                 'getting {}:{}'.format(self._instrument.name, self.name),)
--> 437             raise e
    438 
    439     @asyncio.coroutine

d:\githubrepos\qcodes\qcodes\instrument\parameter.py in get(self)
    429     def get(self):
    430         try:
--> 431             value = self._get()
    432             self._save_val(value)
    433             return value

d:\githubrepos\qcodes\qcodes\utils\sync_async.py in call(self, *args)
    202     def call(self, *args):
    203         self.validate_arg_count(args)
--> 204         return self.exec_function(*args)
    205 
    206     @asyncio.coroutine

d:\githubrepos\qcodes\qcodes\instrument\visa.py in get_idn(self)
     55     def get_idn(self):
     56         """Parse a standard VISA '*IDN?' response into an ID dict."""
---> 57         idstr = self.ask('*IDN?')
     58         try:
     59             # form is supposed to be comma-separated, but we've seen

d:\githubrepos\qcodes\qcodes\instrument_drivers\QuTech\IVVI.py in ask(self, message, raw)
    234         '''
    235         # Protocol knows about the expected length of the answer
--> 236         message_len = self.write(message, raw=raw)
    237         return self.read(message_len=message_len)
    238 

d:\githubrepos\qcodes\qcodes\instrument_drivers\QuTech\IVVI.py in write(self, message, raw)
    222             message_len = len(message)+2
    223             error_code = bytes([0])
--> 224             message = bytes([message_len]) + error_code + message
    225         self.visa_handle.write_raw(message)
    226 

TypeError: ("can't concat bytes to str", 'getting IVVI:IDN')
```


Resolving patch:
diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -55,15 +55,13 @@ def __init__(self, name, address, reset=False, numdacs=16, dac_step=10,
             raise ValueError('numdacs must be a positive multiple of 4, '
                              'not {}'.format(numdacs))
 
-        self.pol_num = np.zeros(self._numdacs)  # corresponds to POS polarity
-        self.set_pol_dacrack('BIP', range(self._numdacs))
-
         # values based on descriptor
         self.visa_handle.baud_rate = 115200
         self.visa_handle.parity = visa.constants.Parity(1)  # odd parity
 
         self.add_parameter('version',
                            get_cmd=self._get_version)
+        
         self.add_parameter('dac voltages',
                            label='Dac voltages',
                            get_cmd=self._get_dacs)
@@ -83,6 +81,10 @@ def __init__(self, name, address, reset=False, numdacs=16, dac_step=10,
 
         self._update_time = 5  # seconds
         self._time_last_update = 0  # ensures first call will always update
+        
+        self.pol_num = np.zeros(self._numdacs)  # corresponds to POS polarity
+        self.set_pol_dacrack('BIP', range(self._numdacs), get_all=False)
+
         t1 = time.time()
 
         # basic test to confirm we are properly connected
@@ -94,6 +96,15 @@ def __init__(self, name, address, reset=False, numdacs=16, dac_step=10,
 
         print('Initialized IVVI-rack in %.2fs' % (t1-t0))
 
+    def get_idn(self):
+        """
+        Overwrites the get_idn function using constants as the hardware
+        does not have a proper *IDN function.
+        """
+        idparts = ['QuTech', 'IVVI', 'None', self.version()]
+
+        return dict(zip(('vendor', 'model', 'serial', 'firmware'), idparts))
+
     def _get_version(self):
         mes = self.ask(bytes([3, 4]))
         v = mes[2]
@@ -263,14 +274,14 @@ def read(self, message_len=None):
         #     raise Exception('IVVI rack exception "%s"' % mes[1])
         return mes
 
-    def set_pol_dacrack(self, flag, channels, getall=True):
+    def set_pol_dacrack(self, flag, channels, get_all=True):
         '''
         Changes the polarity of the specified set of dacs
 
         Input:
             flag (string) : 'BIP', 'POS' or 'NEG'
             channel (int) : 0 based index of the rack
-            getall (boolean): if True (default) perform a get_all
+            get_all (boolean): if True (default) perform a get_all
 
         Output:
             None
@@ -284,7 +295,7 @@ def set_pol_dacrack(self, flag, channels, getall=True):
             self.pol_num[ch-1] = val
             # self.set_parameter_bounds('dac%d' % (i+1), val, val + self.Fullrange.0)
 
-        if getall:
+        if get_all:
             self.get_all()
 
     def get_pol_dac(self, channel):
@@ -318,7 +329,6 @@ def get_func():
             return fun(ch)
         return get_func
 
-
 '''
 RS232 PROTOCOL
 -----------------------


Test patch: