diff --git a/docs/examples/Keithley_example.ipynb b/docs/examples/Keithley_example.ipynb
new file mode 100644
index 000000000000..1d9799c229f8
--- /dev/null
+++ b/docs/examples/Keithley_example.ipynb
@@ -0,0 +1,519 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Example script for Keithley driver"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/*\r\n",
+ " * Qcodes Jupyter/IPython widgets\r\n",
+ " */\r\n",
+ "require([\r\n",
+ " 'nbextensions/widgets/widgets/js/widget',\r\n",
+ " 'nbextensions/widgets/widgets/js/manager'\r\n",
+ "], function (widget, manager) {\r\n",
+ "\r\n",
+ " var UpdateView = widget.DOMWidgetView.extend({\r\n",
+ " render: function() {\r\n",
+ " window.MYWIDGET = this;\r\n",
+ " this._interval = 0;\r\n",
+ " this.update();\r\n",
+ " },\r\n",
+ " update: function() {\r\n",
+ " this.display(this.model.get('_message'));\r\n",
+ " this.setInterval();\r\n",
+ " },\r\n",
+ " display: function(message) {\r\n",
+ " /*\r\n",
+ " * display method: override this for custom display logic\r\n",
+ " */\r\n",
+ " this.el.innerHTML = message;\r\n",
+ " },\r\n",
+ " remove: function() {\r\n",
+ " clearInterval(this._updater);\r\n",
+ " },\r\n",
+ " setInterval: function(newInterval) {\r\n",
+ " var me = this;\r\n",
+ " if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+ " if(newInterval===me._interval) return;\r\n",
+ "\r\n",
+ " me._interval = newInterval;\r\n",
+ "\r\n",
+ " if(me._updater) clearInterval(me._updater);\r\n",
+ "\r\n",
+ " if(me._interval) {\r\n",
+ " me._updater = setInterval(function() {\r\n",
+ " me.send({myupdate: true});\r\n",
+ " if(!me.model.comm_live) {\r\n",
+ " console.log('missing comm, canceling widget updates', me);\r\n",
+ " clearInterval(me._updater);\r\n",
+ " }\r\n",
+ " }, me._interval * 1000);\r\n",
+ " }\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+ "\r\n",
+ " var HiddenUpdateView = UpdateView.extend({\r\n",
+ " display: function(message) {\r\n",
+ " this.$el.hide();\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+ "\r\n",
+ " var SubprocessView = UpdateView.extend({\r\n",
+ " render: function() {\r\n",
+ " var me = window.SPVIEW = this;\r\n",
+ " me._interval = 0;\r\n",
+ " me._minimize = '';\r\n",
+ " me._restore = '';\r\n",
+ "\r\n",
+ " // in case there is already an outputView present,\r\n",
+ " // like from before restarting the kernel\r\n",
+ " $('.qcodes-output-view').not(me.$el).remove();\r\n",
+ "\r\n",
+ " me.$el\r\n",
+ " .addClass('qcodes-output-view')\r\n",
+ " .attr('qcodes-state', 'docked')\r\n",
+ " .html(\r\n",
+ " '
' +\r\n",
+ " ''\r\n",
+ " );\r\n",
+ "\r\n",
+ " me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+ " me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+ " me.outputArea = me.$el.find('pre');\r\n",
+ " me.subprocessList = me.$el.find('span');\r\n",
+ " me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+ "\r\n",
+ " me.clearButton.click(function() {\r\n",
+ " me.outputArea.html('');\r\n",
+ " me.clearButton.addClass('disabled');\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.abortButton.click(function() {\r\n",
+ " me.send({abort: true});\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.$el.find('.js-state').click(function() {\r\n",
+ " var oldState = me.$el.attr('qcodes-state'),\r\n",
+ " state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+ " .split('-')[1].split(' ')[0];\r\n",
+ "\r\n",
+ " // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+ " // some other bit of code resets the parent after render if I do it there.\r\n",
+ " // To be safe, just do it on every state click.\r\n",
+ " me.$el.appendTo('body');\r\n",
+ "\r\n",
+ " if(oldState === 'floated') {\r\n",
+ " me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+ " }\r\n",
+ "\r\n",
+ " me.$el.attr('qcodes-state', state);\r\n",
+ "\r\n",
+ " if(state === 'floated') {\r\n",
+ " me.$el.draggable().css({\r\n",
+ " left: window.innerWidth - me.$el.width() - 15,\r\n",
+ " top: window.innerHeight - me.$el.height() - 10\r\n",
+ " });\r\n",
+ " }\r\n",
+ " });\r\n",
+ "\r\n",
+ " $(window).resize(function() {\r\n",
+ " if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+ " var position = me.$el.position(),\r\n",
+ " minVis = 20,\r\n",
+ " maxLeft = window.innerWidth - minVis,\r\n",
+ " maxTop = window.innerHeight - minVis;\r\n",
+ "\r\n",
+ " if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+ " if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+ " }\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.update();\r\n",
+ " },\r\n",
+ "\r\n",
+ " display: function(message) {\r\n",
+ " if(message) {\r\n",
+ " var initialScroll = this.outputArea.scrollTop();\r\n",
+ " this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+ " var scrollBottom = this.outputArea.scrollTop();\r\n",
+ "\r\n",
+ " if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+ " this.$el.find('.qcodes-docked').click();\r\n",
+ " // always scroll to the bottom if we're restoring\r\n",
+ " // because of a new message\r\n",
+ " initialScroll = scrollBottom;\r\n",
+ " }\r\n",
+ "\r\n",
+ " this.outputArea.append(message);\r\n",
+ " this.clearButton.removeClass('disabled');\r\n",
+ "\r\n",
+ " // if we were scrolled to the bottom initially, make sure\r\n",
+ " // we stay that way.\r\n",
+ " this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+ " this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+ " }\r\n",
+ "\r\n",
+ " var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+ " this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+ " this.subprocessList.text(processes);\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+ "});\r\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "import time\n",
+ "import numpy as np\n",
+ "from imp import reload\n",
+ "\n",
+ "import qcodes as qc\n",
+ "\n",
+ "qc.set_mp_method('spawn') # force Windows behavior on mac\n",
+ "\n",
+ "# this makes a widget in the corner of the window to show and control\n",
+ "# subprocesses and any output they would print to the terminal\n",
+ "qc.show_subprocess_widget()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Keithley driver\n",
+ "\n",
+ "What to do:\n",
+ " \n",
+ "* implement add functionality of the driver\n",
+ "* add documentation to the functions\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import qcodes.instrument_drivers\n",
+ "import qcodes.instrument_drivers.tektronix.Keithley_2700 as keith; reload(keith)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.17s\n"
+ ]
+ }
+ ],
+ "source": [
+ "k1 = keith.Keithley_2700('Keithley', 'GPIB1::15::INSTR')\n",
+ "k1.add_parameter('READ', get_cmd='READ?', label='Keithley value', get_parser=float)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "current mode: VOLT:DC\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('current mode: %s' % k1.get('mode'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "measure: -0.095112\n",
+ "measure: -0.104225\n",
+ "measure: -0.112567\n",
+ "measure: -0.129525\n",
+ "measure: -0.137803\n",
+ "measure: -0.146068\n"
+ ]
+ }
+ ],
+ "source": [
+ "for i in range(6):\n",
+ " print('measure: %.6f' % k1.readnext() )"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[]"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "station = qc.Station('Keithley')\n",
+ "\n",
+ "# could measure any number of things by adding arguments to this\n",
+ "# function call, but here we're just measuring one, the meter mode\n",
+ "station.set_measurement(k1.mode)\n",
+ "\n",
+ "qc.active_children()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['VOLT:DC']"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "station.measure()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Get integration time in Number of PowerLine Cycles.\n",
+ "To get the integrationtime in seconds, use get_integrationtime().\r\n",
+ "Parameter class:\n",
+ "* `name` nplc\r\n",
+ "* `label` nplc\r\n",
+ "* `units` APER\r\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(k1.nplc.__doc__)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Test whether the object can be pickled"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "ValueError",
+ "evalue": "ctypes objects containing pointers cannot be pickled",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mtempfile\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mtempfile\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTemporaryFile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'wb'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0moutput\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mpickle\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdump\u001b[0m\u001b[1;33m(\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mk1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moutput\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mValueError\u001b[0m: ctypes objects containing pointers cannot be pickled"
+ ]
+ }
+ ],
+ "source": [
+ "import pickle\n",
+ "import tempfile\n",
+ "with tempfile.TemporaryFile('wb') as output:\n",
+ " pickle.dump( (k1, ), output)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.5.1"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/qcodes/instrument/function.py b/qcodes/instrument/function.py
index 0ef731224729..ee938d53b1a5 100644
--- a/qcodes/instrument/function.py
+++ b/qcodes/instrument/function.py
@@ -46,16 +46,22 @@ class Function(Metadatable):
If None (default), will not wait for or read any response
NOTE: parsers only apply if call_cmd is a string. The function forms
of call_cmd and async_call_cmd should do their own parsing.
+ docstring: documentation string for the __doc__ field of the object
+ The __doc__ field of the instance is used by some help systems,
+ but not all (particularly not builtin `help(...)`)
'''
def __init__(self, name, instrument=None,
call_cmd=None, async_call_cmd=None,
args=[], arg_parser=None, return_parser=None,
- **kwargs):
+ docstring=None, **kwargs):
super().__init__(**kwargs)
self._instrument = instrument
self.name = name
+ if docstring is not None:
+ self.__doc__ = docstring
+
self._set_args(args)
self._set_call(call_cmd, async_call_cmd,
arg_parser, return_parser)
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index a06b37eb58df..d596321ae5d1 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -37,6 +37,7 @@
import time
import asyncio
import logging
+import os
from qcodes.utils.helpers import (permissive_range, wait_secs,
DelegateAttributes)
@@ -134,7 +135,7 @@ def __init__(self,
units=None,
size=None, sizes=None,
setpoints=None, setpoint_names=None, setpoint_labels=None,
- vals=None, **kwargs):
+ vals=None, docstring=None, **kwargs):
super().__init__(**kwargs)
if names is not None:
@@ -144,7 +145,13 @@ def __init__(self,
# and names are the items it returns
self.names = names
self.labels = names if labels is None else names
- self.units = units if units is not None else ['']*len(names)
+ self.units = units if units is not None else [''] * len(names)
+
+ self.__doc__ = os.linesep.join((
+ 'Parameter class:',
+ '* `names` %s' % ', '.join(self.names),
+ '* `labels` %s' % ', '.join(self.labels),
+ '* `units` %s' % ', '.join(self.units)))
elif name is not None:
self.name = name
@@ -154,6 +161,14 @@ def __init__(self,
# vals / validate only applies to simple single-value parameters
self._set_vals(vals)
+ # generate default docstring
+ self.__doc__ = os.linesep.join((
+ 'Parameter class:',
+ '* `name` %s' % self.name,
+ '* `label` %s' % self.label,
+ '* `units` %s' % self.units,
+ '* `vals` %s' % repr(self._vals)))
+
else:
raise ValueError('either name or names is required')
@@ -167,6 +182,9 @@ def __init__(self,
self.setpoint_names = setpoint_names
self.setpoint_labels = setpoint_labels
+ if docstring is not None:
+ self.__doc__ = docstring + os.linesep + self.__doc__
+
# record of latest value and when it was set or measured
# what exactly this means is different for different subclasses
# but they all use the same attributes so snapshot is consistent.
@@ -269,6 +287,8 @@ class StandardParameter(Parameter):
sweep_delay: time (in seconds) to wait after each sweep step
max_val_age: max time (in seconds) to trust a saved value from
this parameter as the starting point of a sweep
+ docstring: documentation string for the __doc__ field of the object
+ The __doc__ field of the instance is used by some help systems, but not all
'''
def __init__(self, name, instrument=None,
get_cmd=None, async_get_cmd=None, get_parser=None,
@@ -289,6 +309,8 @@ def __init__(self, name, instrument=None,
self._set_mapping = val_mapping
set_parser = self._set_mapping.__getitem__
+ if get_parser is not None and not isinstance(get_cmd, str):
+ logging.warning('get_parser is set, but will not be used')
super().__init__(name=name, vals=vals, **kwargs)
self._instrument = instrument
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
new file mode 100644
index 000000000000..39e11a2b8a04
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -0,0 +1,398 @@
+# Keithley_2700.py driver for Keithley 2700 DMM
+#
+# Pieter Eendebak , 2016 (adapt to Qcodes framework)
+# Pieter de Groot , 2008
+# Martijn Schaafsma , 2008
+# Reinier Heeres , 2008
+#
+# Update december 2009:
+# Michiel Jol
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import time
+import logging
+from functools import partial
+
+from qcodes.instrument.visa import VisaInstrument
+from qcodes.utils.validators import Strings as StringValidator
+from qcodes.utils.validators import Ints as IntsValidator
+from qcodes.utils.validators import Numbers as NumbersValidator
+
+
+# %% Helper functions
+
+
+def bool_to_str(val):
+ '''
+ Function to convert boolean to 'ON' or 'OFF'
+ '''
+ if val:
+ return "ON"
+ else:
+ return "OFF"
+
+
+# %% Driver for Keithley_2700
+
+def parseint(v):
+ logging.debug('parseint: %s -> %d' % (v, int(v)))
+ return int(v)
+
+
+def parsebool(v):
+ r = bool(int(v))
+ logging.debug('parsetobool: %s -> %d' % (v, r))
+ return r
+
+
+def parsestr(v):
+ return v.strip().strip('"')
+
+
+class Keithley_2700(VisaInstrument):
+ '''
+ This is the qcodes driver for the Keithley_2700 Multimeter
+
+ Usage: Initialize with
+ = = Keithley_2700(, address='', reset=,
+ change_display=, change_autozero=)
+
+ Status: beta-version.
+
+ This driver will most likely work for multiple Keithley SourceMeters.
+
+ This driver does not contain all commands available, but only the ones
+ most commonly used.
+ '''
+ def __init__(self, name, address, reset=False):
+ t0 = time.time()
+ super().__init__(name, address)
+
+ self.add_parameter('IDN', get_cmd='*IDN?')
+
+ self._modes = ['VOLT:AC', 'VOLT:DC', 'CURR:AC', 'CURR:DC', 'RES',
+ 'FRES', 'TEMP', 'FREQ']
+ # self._change_display = change_display
+ # self._change_autozero = change_autozero
+ self._averaging_types = ['MOV', 'REP']
+ self._trigger_sent = False
+
+ # Add parameters to wrapper
+ self.add_parameter('mode',
+ get_cmd=':CONF?',
+ get_parser=parsestr,
+ set_cmd=':CONF:{}',
+ vals=StringValidator())
+
+ self.add_parameter('trigger_count',
+ get_cmd=self._mode_par('INIT', 'CONT'),
+ get_parser=int,
+ set_cmd=self._mode_par_value('INIT', 'CONT', '{}'),
+ vals=IntsValidator(),
+ units='#')
+ self.add_parameter('trigger_delay',
+ get_cmd=self._mode_par('TRIG', 'DEL'),
+ get_parser=float,
+ set_cmd=self._mode_par_value('TRIG', 'DEL', '{}'),
+ vals=NumbersValidator(min_value=0,
+ max_value=999999.999),
+ units='s')
+
+ self.add_parameter('trigger_continuous',
+ get_cmd=self._mode_par('INIT', 'CONT'),
+ get_parser=parsebool,
+ set_cmd=self._mode_par_value('INIT', 'CONT', '{}'),
+ set_parser=bool_to_str)
+ self.add_parameter('display',
+ get_cmd=self._mode_par('DISP', 'ENAB'),
+ get_parser=parsebool,
+ set_cmd=self._mode_par_value('DISP', 'ENAB', '{}'),
+ set_parser=bool_to_str)
+
+ self.add_parameter('averaging',
+ get_cmd=partial(self._current_mode_get, 'AVER:STAT',
+ parser=parsebool),
+ set_cmd=partial(self._current_mode_set,
+ par='AVER:STAT'),
+ set_parser=bool_to_str)
+
+ self.add_parameter('digits',
+ get_cmd=partial(self._current_mode_get, 'DIG',
+ parser=int),
+ set_cmd=partial(self._current_mode_set, par='DIG'))
+
+ self.add_parameter('nplc',
+ get_cmd=partial(self._current_mode_get, 'NPLC',
+ parser=float),
+ set_cmd=partial(self._current_mode_set, par='NPLC',
+ mode=None),
+ units='APER',
+ docstring=('Get integration time in Number of '
+ 'PowerLine Cycles.\n'
+ 'To get the integrationtime in seconds, '
+ 'use get_integrationtime().'))
+
+ self.add_parameter('range',
+ get_cmd=partial(self._current_mode_get, 'RANG',
+ parser=float),
+ set_cmd=partial(self._current_mode_set, par='RANG'),
+ units='RANG',
+ docstring=('Sets the measurement range.\n'
+ 'Note that not only a discrete set of '
+ 'ranges can be set (see the manual for '
+ 'details).'))
+
+ self.add_parameter('integrationtime',
+ get_cmd=partial(self._current_mode_get, 'APER',
+ parser=float),
+ set_cmd=partial(self._current_mode_set, par='APER',
+ mode=None),
+ units='s',
+ vals=NumbersValidator(min_value=2e-4, max_value=1.),
+ docstring=('Get integration time in seconds.\n'
+ 'To get the integrationtime as a Number '
+ 'of PowerLine Cycles, use get_nplc().'))
+
+ '''
+ self.add_parameter('trigger_source',
+ flags=Instrument.FLAG_GETSET,
+ units='')
+ self.add_parameter('trigger_timer',
+ flags=Instrument.FLAG_GETSET,
+ units='s', minval=0.001, maxval=99999.999, type=float)
+ self.add_parameter('readval', flags=Instrument.FLAG_GET,
+ units='arb.unit',
+ type=float,
+ tags=['measure'])
+ self.add_parameter('readlastval', flags=Instrument.FLAG_GET,
+ units='arb.unit',
+ type=float,
+ tags=['measure'])
+ self.add_parameter('readnextval', flags=Instrument.FLAG_GET,
+ units='arb.unit',
+ type=float,
+ tags=['measure'])
+ self.add_parameter('autozero', flags=Instrument.FLAG_GETSET,
+ type=bool)
+ self.add_parameter('averaging_window',
+ flags=Instrument.FLAG_GETSET,
+ units='%', type=float, minval=0, maxval=10)
+ self.add_parameter('averaging_count',
+ flags=Instrument.FLAG_GETSET,
+ units='#', type=int, minval=1, maxval=100)
+ self.add_parameter('averaging_type',
+ flags=Instrument.FLAG_GETSET,
+ type=bytes, units='')
+ self.add_parameter('autorange',
+ flags=Instrument.FLAG_GETSET,
+ units='',
+ type=bool)
+ '''
+
+ # add functions
+ self.add_function('readnext',
+ units='arb.unit',
+ call_cmd=':DATA:FRESH?',
+ return_parser=float)
+
+ if reset:
+ self.reset()
+ else:
+ self.get_all()
+ self.set_defaults()
+
+ t1 = time.time()
+ print('Connected to: ',
+ self.get('IDN').replace(',', ', ').replace('\n', ' '),
+ 'in %.2fs' % (t1-t0))
+
+ def get_all(self):
+ '''
+ Reads all relevant parameters from instrument
+
+ Input:
+ None
+
+ Output:
+ None
+ '''
+ logging.info('Get all relevant data from device')
+
+ for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging',
+ 'digits', 'nplc', 'integrationtime', 'range', 'display']:
+ logging.debug('get %s' % p)
+ par = getattr(self, p)
+ par.get()
+
+ # self.get_trigger_delay()
+ # self.get_trigger_source()
+ # self.get_trigger_timer()
+ # self.get_autozero()
+ # self.get_averaging_window()
+ # self.get_averaging_count()
+ # self.get_averaging_type()
+ # self.get_autorange()
+
+ def _current_mode_get(self, par, mode=None, parser=None):
+ cmd = self._mode_par(mode, par)
+ r = self.ask(cmd)
+ if parser is not None:
+ r = parser(r)
+ return r
+
+ def _current_mode_set(self, value, par, mode=None):
+ cmd = self._mode_par_value(mode, par, value)
+ return self.write(cmd)
+
+ # --------------------------------------
+ # functions
+ # --------------------------------------
+
+ def set_mode_volt_dc(self):
+ '''
+ Set mode to DC Voltage
+
+ Input:
+ None
+
+ Output:
+ None
+ '''
+ logging.debug('Set mode to DC Voltage')
+ self.mode.set('VOLT:DC')
+
+ def set_defaults(self):
+ '''
+ Set to driver defaults:
+ Output=data only
+ Mode=Volt:DC
+ Digits=7
+ Trigger=Continous
+ Range=10 V
+ NPLC=1
+ Averaging=off
+ '''
+
+ self.write('SYST:PRES')
+ self.write(':FORM:ELEM READ')
+ # Sets the format to only the read out, all options are:
+ # READing = DMM reading, UNITs = Units,
+ # TSTamp = Timestamp, RNUMber = Reading number,
+ # CHANnel = Channel number, LIMits = Limits reading
+
+ self.set_mode_volt_dc()
+ self.digits.set(7)
+ self.trigger_continuous.set(True)
+ self.range.set(10)
+ self.nplc.set(1)
+ self.averaging.set(False)
+ return
+
+ def _determine_mode(self, mode):
+ '''
+ Return the mode string to use.
+ If mode is None it will return the currently selected mode.
+ '''
+ logging.debug('Determine mode with mode=%s' % mode)
+ if mode is None:
+ mode = self.mode.get_latest() # _mode(query=False)
+ if mode not in self._modes and mode not in ('INIT', 'TRIG', 'SYST',
+ 'DISP'):
+ logging.warning('Invalid mode %s, assuming current' % mode)
+ mode = self.mode.get_latest()
+ logging.debug('Determine mode: mode=%s' % mode)
+ return mode
+
+ def set_mode(self, mode):
+ '''
+ Set the mode to the specified value
+
+ Input:
+ mode (string) : mode to be set. Choose from self._modes
+
+ Output:
+ None
+ '''
+
+ logging.debug('Set mode to %s', mode)
+ if mode in self._modes:
+ string = ':CONF:%s' % mode
+ self._visainstrument.write(string)
+
+ if mode.startswith('VOLT'):
+ self._change_units('V')
+ elif mode.startswith('CURR'):
+ self._change_units('A')
+ elif mode.startswith('RES'):
+ self._change_units('Ohm')
+ elif mode.startswith('FREQ'):
+ self._change_units('Hz')
+
+ else:
+ logging.error('invalid mode %s' % mode)
+
+ # Get all values again because some parameters depend on mode
+ self.get_all()
+
+ def _mode_par_value(self, mode, par, val):
+ '''
+ For internal use only!!
+ Create command string based on current mode
+
+ Input:
+ mode (string) : The mode to use
+ par (string) : Parameter
+ val (depends) : Value
+
+ Output:
+ None
+ '''
+ mode = self._determine_mode(mode)
+ string = ':%s:%s %s' % (mode, par, val)
+ return string
+
+ def _mode_par(self, mode, par):
+ '''
+ For internal use only!!
+ Create command string based on current mode
+
+ Input:
+ mode (string) : The mode to use
+ par (string) : Parameter
+ val (depends) : Value
+
+ Output:
+ None
+ '''
+ mode = self._determine_mode(mode)
+ string = ':%s:%s?' % (mode, par, )
+ return string
+
+ def reset(self):
+ '''
+ Resets instrument to default values
+
+ Input:
+ None
+
+ Output:
+ None
+ '''
+ logging.debug('Resetting instrument')
+ self._visainstrument.write('*RST')
+ self.get_all()
+
+
\ No newline at end of file