Example of Handling Events
- Updated2025-01-24
- 5 minute(s) read
When dealing with instrument communication, it is very common for the instrument to require service from the controller when the controller is not actually looking at the device. A device can notify the controller via a service request (SRQ), interrupt, or a signal. Each of these is an asynchronous event, or simply an event. In VISA, you can handle these and other events through either callbacks or a software queue.
Handling Events Through Callbacks
Using callbacks, you can have sections of code that are never explicitly called by the program, but instead are called by the VISA driver whenever an event occurs. Due to their asynchronous nature, callbacks can be difficult to incorporate into a traditional, sequential flow program. Therefore, we recommend the queuing method of handling events for new users.
Handling Events Through Queuing
When using a software queue, the VISA driver detects the asynchronous event but does not alert the program to the occurrence. Instead, the driver maintains a list of events that have occurred so that the program can retrieve the information later. With this technique, the program can periodically poll the driver for event information or halt the program until the event has occurred. The following example programs an oscilloscope to capture a waveform. When the waveform is complete, the instrument generates a VXI interrupt, so the program must wait for the interrupt before trying to read the data.
Handling Events Example (C)
#include "visa.h" int main(void) { ViStatus status; /* For checking errors */ ViSession defaultRM, instr; /* Communication channels */ ViEvent eventData; /* To hold event info */ ViUInt16 statID; /* Interrupt Status ID */ /* Begin by initializing the system */ status = viOpenDefaultRM(&defaultRM); if (status < VI_SUCCESS) { /* Error Initializing VISA...exiting */ return -1; } /* Open communication with VXI Device at Logical Address 16 */ /* NOTE: For simplicity, we will not show error checking */ status = viOpen(defaultRM, "VXI0::16::INSTR", VI_NULL, VI_NULL, &instr); /* Enable the driver to detect the interrupts */ status = viEnableEvent(instr, VI_EVENT_VXI_SIGP, VI_QUEUE, VI_NULL); /* Send the commands to the oscilloscope to capture the */ /* waveform and interrupt when done */ status = viWaitOnEvent(instr, VI_EVENT_VXI_SIGP, 5000, VI_NULL, &eventData); if (status < VI_SUCCESS) { /* No interrupts received after 5000 ms timeout */ viClose(defaultRM); return -1; } /* Obtain the information about the event and then destroy the */ /* event. In this case, we want the status ID from the interrupt. */ status = viGetAttribute(eventData, VI_ATTR_SIGP_STATUS_ID, &statID); status = viClose(eventData); /* Your code should read data from the instrument and process it.*/ /* Stop listening to events */ status = viDisableEvent(instr, VI_EVENT_VXI_SIGP, VI_QUEUE); /* Close down the system */ status = viClose(instr); status = viClose(defaultRM); return 0; }
Handling Events Example (VB)
Private Sub vbMain() Dim stat As ViStatus Dim dfltRM As ViSession Dim sesn As ViSession Dim eType As ViEventType Dim eData As ViEvent Dim statID As Integer Rem Begin by initializing the system stat = viOpenDefaultRM(dfltRM) If (stat < VI_SUCCESS) Then Rem Error initializing VISA...exiting Exit Sub End If Rem Open communication with VXI Device at Logical Address 16 Rem NOTE: For simplicity, we will not show error checking stat = viOpen(dfltRM, "VXI0::16::INSTR", VI_NULL, VI_NULL, sesn) Rem Enable the driver to detect the interrupts stat = viEnableEvent(sesn, VI_EVENT_VXI_SIGP, VI_QUEUE, VI_NULL) Rem Send the commands to the oscilloscope to capture the Rem waveform and interrupt when done stat = viWaitOnEvent(sesn, VI_EVENT_VXI_SIGP, 5000, eType, eData) If (stat < VI_SUCCESS) Then Rem No interrupts received after 5000 ms timeout stat = viClose (dfltRM) Exit Sub End If Rem Obtain the information about the event and then destroy the Rem event. In this case, we want the status ID from the interrupt. stat = viGetAttribute(eData, VI_ATTR_SIGP_STATUS_ID, statID) stat = viClose(eData) Rem Your code should read data from the instrument and process it. Rem Stop listening to events stat = viDisableEvent(sesn, VI_EVENT_VXI_SIGP, VI_QUEUE) Rem Close down the system stat = viClose(sesn) stat = viClose(dfltRM) End Sub
Handling Events Example Discussion
Programming with events presents some new functions to use. The first two functions you notice are viEnableEvent() and viDisableEvent(). These functions tell the VISA driver which events to listen for—in this case VI_EVENT_VXI_SIGP, which covers both VXI interrupts and VXI signals. In addition, these functions tell the driver how to handle events when they occur. In this example, the driver is instructed to queue (VI_QUEUE) the events until asked for them. Notice that instr is also supplied to the functions, since VISA performs event handling on a per-communication-channel basis.
Once the driver is ready to handle events, you are free to write code that will result in an event being generated. In the example above, this is shown as a comment block because the exact code depends on the device. After you have set the device up to interrupt, the program must wait for the interrupt. This is accomplished by the viWaitOnEvent() function. Here you specify what events you are waiting for and how long you want to wait. The program then blocks, and that thread performs no other functions, until the event occurs. Therefore, after the viWaitOnEvent() call returns, either it has timed out (5 s in the above example) or it has caught the interrupt. After some error checking to determine whether it was successful, you can obtain information from the event through viGetAttribute(). When you are finished with the event data structure (eventData), destroy it by calling viClose() on it. You can now continue with the program and retrieve the data. The rest of the program is the same as the previous examples.
Notice the difference in the way you can shut down the program if a timeout has occurred. You do not need to close the communication channel with the device, but only with the VISA driver. You can do this because when a driver channel (defaultRM) is closed, the VISA driver closes all I/O channels opened with it. So when you need to shut down a program quickly, as in the case of an error, you can simply close the channel to the driver and VISA handles the rest for you. However, VISA does not clean up anything not associated with VISA, such as memory you have allocated. You are still responsible for those items.