Closed lupien closed 9 years ago
Sounds really good. Just one idea, how about if we make the API even easier for the end user. Maybe we can leave this functions as mid-level functions but in the ResourceManager (or Maybe in the resource) add a function that returns a random number or string (as the handler id) which should then be used by the user to uninstall the handler. Moreover, we could have an API to list the active handlers.
The handlers are related to the session so if you move them, it should be to the resource. The resource already has the basic versions install_handler and uninstall_handler (they could be left to the visalib).
The user interface is not too bad if the documentation is clearer. These are not functions that the user will use often interactively, however they are used in more advanced programs that communicates to many instruments in parallel (I use it like that). The information is already there for listing the active handlers. You cannot just return a string or a number, the user needs the converted (ctypes) user_handle. You could return a new object with a method to uninstall that is automatically called on del and that contains the necessary information (ctypes, handler function, ...) but that is probably more complicated than needed.
If you move the install/uninstall _visa_handler, I would also add to the resource the event functions since the handlers are useless without them (enable_event, discard_events, disable_event, wait_on_event).
And if you are going to move stuff, there is some stuff in the gpib resource that is more general according the the Visa-lib spec: assert_trigger (already in MessageBasedResource, duplicated in gpib), control_ren (should be available for USB, HiSLIP) the event stuff (should be available to all resources, gpib has __switch_events_off, wait_for_srq)
Can you post a short example of how you are using this. (assuming the modified PyVISA)? Thanks!
Here is an example of it:
import pyvisa
import time
rm = pyvisa.ResourceManager()
v = rm.get_instrument('USB::0x0957::0x0B0B::MY55555555') # This is an agilent EXA spectrum analyser
v.write('*cls') # clear the status/event registers
v.write('*ese 1;*sre 32') # enable RQS from event status and enable event Operation Complete
def handler_func(session, event_type, context, user_handle):
s = v.read_stb()
if user_handle is not None:
user_handle = user_handle.contents.value
print 'session_id=%s (==%s event_session), type=%s, context=%s, user_handle=%s, stb=%s'%( v.session, session.value, event_type, context.value, user_handle, int(s))
return pyvisa.constants.VI_SUCCESS
# install handlers
user_handle_None = v.visalib.install_visa_handler(v.session, pyvisa.constants.VI_EVENT_SERVICE_REQ, handler_func, None)
user_handle_1 = v.visalib.install_visa_handler(v.session, pyvisa.constants.VI_EVENT_SERVICE_REQ, handler_func, 1)
user_handle_1 # shows: c_long(1)
user_handle_str = v.visalib.install_visa_handler(v.session, pyvisa.constants.VI_EVENT_SERVICE_REQ, handler_func, 'test_str')
# enable Service Request events
v.visalib.enable_event(v.session, pyvisa.constants.VI_EVENT_SERVICE_REQ, pyvisa.constants.VI_HNDLR)
# generate the events (assumes the connected device handles *OPC instruction)
foo=v.write('*OPC'); time.sleep(1); foo
## This is the ouput for me
#session_id=48735064 (==48735064 event_session), type=1073684491, context=48826820, user_handle=test_str, stb=96
#session_id=48735064 (==48735064 event_session), type=1073684491, context=48826820, user_handle=1, stb=32
#session_id=48735064 (==48735064 event_session), type=1073684491, context=48826820, user_handle=None, stb=32
#(6L, <StatusCode.success: 0>)
# Change user_handle_1, remove str handler, reset registers and generate new event
user_handle_1.value=5
v.visalib.uninstall_visa_handler(v.session, pyvisa.constants.VI_EVENT_SERVICE_REQ, handler_func, user_handle_str)
int(v.query('*esr?')) # returns 1
foo=v.write('*OPC'); time.sleep(1); foo
## This is the ouput for me
#session_id=48735064 (==48735064 event_session), type=1073684491, context=48826820, user_handle=5, stb=32
#session_id=48735064 (==48735064 event_session), type=1073684491, context=48826820, user_handle=None, stb=32
#(6L, <StatusCode.success: 0>)
Tell me if you need something different.
Also something to be careful about, I think I remember an older version of NI-Visa would not allow the use of handlers on GPIB, but I just tested it and it seems to work now.
My real use of the handlers is to start long acquisition (can be in minutes) on many instruments (often INIT scpi commands) and then wait for the completion before fetching the data. So I would use v.write('INIT;*OPC')
then my handler would launch the data transfer.
This avoids timeouts (if trying to download data before it is available), and allows many instruments to work in parallel (not wasting time doing things in sequence), waiting the minimum time.
Excellent. (By the way, it would be great if you can contribute something like this to the docs)
A few ideas that might clean up the API:
install_handler
, uninstall_handler
, enable_event
, disable_event
, etc.
For example, it possible that uninstall_handler
only takes the user handler and gets the rest from an internal dictionary.If you would like to submit a Pull request, would be great. I will be very happy to quickly review an merge it.
I am closing this as we have already the PR.
The uninstall_visa_handler function of VisaLibraryBase (highlevel.py) always fails because it calls viUninstallHandler with the python function instead of the ctypes wrapped one.
Fixing that, other problems show up. If None was used as the user_handle (the default), it can't be removed (pyvisa 1.4 had the same problem) and if the last handler installed did not have the same ctypes user_handle as for the uninstall call it will also fail (need to call set_user_handle_type to make the definitions match).
So here is how I would fix them (I tested them, and it fixes all my problems): highlevel.py VisaLibraryBase
and ctwrapper/functions.py
or the diffs