1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
.. _advanced-backends:
A frontend for multiple backends
================================
.. include:: ../substitutions.sub
A small historical note might help to make this section clearer. So bear with
with me for a couple of lines. Originally PyVISA was a Python wrapper to the
VISA library. More specifically, it was :py:mod:`ctypes` wrapper around the
NI-VISA. This approach worked fine but made it difficult to develop other ways
to communicate with instruments in platforms where NI-VISA was not available.
Users had to change their programs to use other packages with different API.
Since 1.6, PyVISA is a frontend to VISA. It provides a nice, Pythonic API and
can connect to multiple backends. Each backend exposes a class derived from
VisaLibraryBase that implements the low-level communication. The ctypes wrapper
around IVI-VISA is the default backend (called **ivi**) and is bundled with
PyVISA for simplicity. In general, IVI-VISA can be NI-VISA, Keysight VISA,
R&S VISA, tekVISA etc.
By default, it calls the library that is installed on your system as VISA library.
You can specify the backend to use when you instantiate the resource manager
using the ``@`` symbol. Remembering that **ivi** is the default, this::
>>> import pyvisa
>>> rm = pyvisa.ResourceManager()
is the same as this::
>>> import pyvisa
>>> rm = pyvisa.ResourceManager('@ivi')
You can still provide the path to the library if needed::
>>> import pyvisa
>>> rm = pyvisa.ResourceManager('/path/to/lib@ivi')
Under the hood, the |ResourceManager| looks for the requested backend and
instantiate the VISA library that it provides.
PyVISA locates backends by name. If you do:
>>> import pyvisa
>>> rm = pyvisa.ResourceManager('@somename')
PyVISA will try to import a package/module named ``pyvisa_somename`` which
should be installed in your system. This is a loosely coupled configuration
free method. PyVISA does not need to know about any backend out there until you
actually try to use it.
You can list the installed backends by running the following code in the
command line::
pyvisa-info
Developing a new Backend
------------------------
What does a minimum backend looks like? Quite simple::
from pyvisa.highlevel import VisaLibraryBase
class MyLibrary(VisaLibraryBase):
pass
WRAPPER_CLASS = MyLibrary
Additionally you can provide a staticmethod named `get_debug_info` that should
return a dictionary of debug information which is printed when you call
``pyvisa-info``
An important aspect of developing a backend is knowing which VisaLibraryBase
method to implement and what API to expose.
A **complete** implementation of a VISA Library requires a lot of functions
(basically almost all level 2 functions as described in
:ref:`advanced-architecture` (there is also a complete list at the bottom of
this page). But a working implementation does not require all of them.
As a **very minimum** set you need:
- **open_default_resource_manager**: returns a session to the Default
Resource Manager resource.
- **open**: Opens a session to the specified resource.
- **close**: Closes the specified session, event, or find list.
- **list_resources**: Returns a tuple of all connected devices matching
query.
(you can get the signature below or here :ref:`api_visalibrarybase`)
.. note::
A |ResourceManager| attribute check for
:class:`pyvisa.highlevel.VisaLibraryBase.open_resource` is implemented
in order to support custom opening handling by the new backend implementation.
But of course you cannot do anything interesting with just this. In general you
will also need:
- **get_attribute**: Retrieves the state of an attribute.
- **set_atribute**: Sets the state of an attribute.
If you need to start sending bytes to MessageBased instruments you will
require:
- **read**: Reads data from device or interface synchronously.
- **write**: Writes data to device or interface synchronously.
For other usages or devices, you might need to implement other functions. Is
really up to you and your needs.
These functions should raise a :class:`pyvisa.errors.VisaIOError` or emit a
:class:`pyvisa.errors.VisaIOWarning` if necessary, and store error code on a
per session basis. This can be done easily by calling
:py:meth:`~pyvisa.highlevel.VisaLibraryBase.handle_return_value` with the session
and return value.
Complete list of level 2 functions to implement::
def read_memory(self, session, space, offset, width, extended=False):
def write_memory(self, session, space, offset, data, width, extended=False):
def move_in(self, session, space, offset, length, width, extended=False):
def move_out(self, session, space, offset, length, data, width, extended=False):
def peek(self, session, address, width):
def poke(self, session, address, width, data):
def assert_interrupt_signal(self, session, mode, status_id):
def assert_trigger(self, session, protocol):
def assert_utility_signal(self, session, line):
def buffer_read(self, session, count):
def buffer_write(self, session, data):
def clear(self, session):
def close(self, session):
def disable_event(self, session, event_type, mechanism):
def discard_events(self, session, event_type, mechanism):
def enable_event(self, session, event_type, mechanism, context=None):
def flush(self, session, mask):
def get_attribute(self, session, attribute):
def gpib_command(self, session, data):
def gpib_control_atn(self, session, mode):
def gpib_control_ren(self, session, mode):
def gpib_pass_control(self, session, primary_address, secondary_address):
def gpib_send_ifc(self, session):
def in_8(self, session, space, offset, extended=False):
def in_16(self, session, space, offset, extended=False):
def in_32(self, session, space, offset, extended=False):
def in_64(self, session, space, offset, extended=False):
def install_handler(self, session, event_type, handler, user_handle):
def list_resources(self, session, query='?*::INSTR'):
def lock(self, session, lock_type, timeout, requested_key=None):
def map_address(self, session, map_space, map_base, map_size,
def map_trigger(self, session, trigger_source, trigger_destination, mode):
def memory_allocation(self, session, size, extended=False):
def memory_free(self, session, offset, extended=False):
def move(self, session, source_space, source_offset, source_width, destination_space,
def move_asynchronously(self, session, source_space, source_offset, source_width,
def move_in_8(self, session, space, offset, length, extended=False):
def move_in_16(self, session, space, offset, length, extended=False):
def move_in_32(self, session, space, offset, length, extended=False):
def move_in_64(self, session, space, offset, length, extended=False):
def move_out_8(self, session, space, offset, length, data, extended=False):
def move_out_16(self, session, space, offset, length, data, extended=False):
def move_out_32(self, session, space, offset, length, data, extended=False):
def move_out_64(self, session, space, offset, length, data, extended=False):
def open(self, session, resource_name,
def open_default_resource_manager(self):
def out_8(self, session, space, offset, data, extended=False):
def out_16(self, session, space, offset, data, extended=False):
def out_32(self, session, space, offset, data, extended=False):
def out_64(self, session, space, offset, data, extended=False):
def parse_resource(self, session, resource_name):
def parse_resource_extended(self, session, resource_name):
def peek_8(self, session, address):
def peek_16(self, session, address):
def peek_32(self, session, address):
def peek_64(self, session, address):
def poke_8(self, session, address, data):
def poke_16(self, session, address, data):
def poke_32(self, session, address, data):
def poke_64(self, session, address, data):
def read(self, session, count):
def read_asynchronously(self, session, count):
def read_stb(self, session):
def read_to_file(self, session, filename, count):
def set_attribute(self, session, attribute, attribute_state):
def set_buffer(self, session, mask, size):
def status_description(self, session, status):
def terminate(self, session, degree, job_id):
def uninstall_handler(self, session, event_type, handler, user_handle=None):
def unlock(self, session):
def unmap_address(self, session):
def unmap_trigger(self, session, trigger_source, trigger_destination):
def usb_control_in(self, session, request_type_bitmap_field, request_id, request_value,
def usb_control_out(self, session, request_type_bitmap_field, request_id, request_value,
def vxi_command_query(self, session, mode, command):
def wait_on_event(self, session, in_event_type, timeout):
def write(self, session, data):
def write_asynchronously(self, session, data):
def write_from_file(self, session, filename, count):
|