Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Gpib events #175

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
46 changes: 44 additions & 2 deletions pyvisa-py/gpib.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,46 @@ def _inner(self):
raise


class GPIBEvent(object):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentionned in my review, I am not sure how to expose this since pyvisa does not expose events. We should perhaps think about how to expose this in pyvisa and how to make it compatible with pyvisa-py.

Copy link
Contributor Author

@tivek tivek Dec 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GPIBEvent is not a user-facing class, it is an implementation detail: PyVisaLibrary stores GPIBEvent objects in the PyVisaLibrary.events dict and passes any get_attribute() and close() calls down to them. Such "attribute query workers" are required pieces of the puzzle to fully conform to pyvisa's handle-based backend interface.

I agree that pyvisa needs a more pythonic way to expose events, and I think it is actually quite straightforward to get there. Currently, events are actually exposed to the user as raw VISA event contexts/handles. This is not very pythonic but is nevertheless there as a public and documented API. Our user can get hold of an event handle in two main ways:

  1. visalib calls the installed event handlers and passes the event handle as a parameter,
  2. Resource.wait_on_event() returns a WaitResponse object which exposes a member called context.

In both cases, the user can find out more about the event by calling visalib.get_attribute(handle, attribute) or close the event using visalib.close(handle). EDIT: ... and this is why GPIBEvent is there, to provide access-by-handle functionality for PyVisaLibrary in order to fully emulate NIVisaLibrary's behavior.

Instead of low-level handles/contexts, pyvisa should give users some kind of an event object that can be queried and knows how to clean up when it is done. The WaitResponse class already fits the bill nicely: all it needs to become user-friendly are get_attribute() and close() methods and renaming it eg. Event. The remaining step is to wrap user-provided event handlers so that they are passed Event objects when called instead of raw event handles.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed this sounds like a plan.

For the work at hand, even if we do not implement event support right away, we can probably set up a generic class that could be used by all resources rather than an explicitly GPIB restricted class, no ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Looks pretty generic actually. If any session needs to compute event attributes on the fly, they can override get_attributes(). Right now I'm struggling with bikeshedding :) I think "Event" should only be the name of the user-facing pyvisa class.

"""A simple event object that holds event attributes.
"""

def __init__(self, attrs):
"""Initialize GPIBEvent with an attribute dictionary.

:param attrs: Event attributes to be stored.
:type attrs: dict or dictionary-like
"""
self.attrs = {attribute: value for attribute, value in attrs.items()}

def __del__(self):
self.close()

def get_attribute(self, attr):
"""Retrieves the state of an attribute.

Corresponds to viGetAttribute function of the VISA library for this particular event.

:param attribute: Event attribute for which the state query is made (see Attributes.*)
:return: The state of the queried attribute, return value describing success.
:rtype: unicode | str | list | int, VISAStatus
"""
try:
return self.attrs[attr], StatusCode.success
except KeyError:
return None, StatusCode.error_nonsupported_attribute

def close(self):
"""Closes the event.

Corresponds to viClose function of the VISA library.

:return: return value of the library call.
:rtype: VISAStatus
"""
return StatusCode.success


def _find_listeners():
"""Find GPIB listeners.
"""
Expand Down Expand Up @@ -514,10 +554,12 @@ def wait_on_event(self, in_event_type, timeout):

# TODO: set event attributes
if 0x100 & event_mask & sta:
self.event_queue.append((constants.VI_EVENT_IO_COMPLETION, {}))
self.event_queue.append(
(constants.VI_EVENT_IO_COMPLETION, GPIBEvent({})))

if gpib.RQS & event_mask & sta:
self.event_queue.append((constants.VI_EVENT_SERVICE_REQ, {}))
self.event_queue.append(
(constants.VI_EVENT_SERVICE_REQ, GPIBEvent({})))

try:
out_event_type, event_data = self.event_queue.pop()
Expand Down