File: backends.rst

package info (click to toggle)
pyvisa 1.14.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,348 kB
  • sloc: python: 12,643; makefile: 133
file content (202 lines) | stat: -rw-r--r-- 9,138 bytes parent folder | download
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):