I spent the day trying to set up an event based message loop. I have a device that supports USBTMC communication. I can read and write to it using FormatedIO read and write methods. I was trying to attach an event to receive and route responses when they come in. However, I had a very hard time finding current documentation that explains the setup.
I have read the Ni Visa .NET reference document at:
C:\Program Files (x86)\IVI Foundation\VISA\Microsoft.NET\Framework32\v4.0.30319\NI VISA.NET 19.0\Documentation\_NINETVISAHelp.chm
However, this doesn't give much useful information about how to accomplish any task.
I found this visa events page but it provided no new information.
An example installed with Measurement Studio I found showed promise.
C:\Users\Public\Documents\National Instruments\NI-VISA\Examples\.NET\19.0\ServiceRequest
They setup events in a way that is intuitive to me.
// The Enable SRQ button writes the string that tells the instrument to
// enable the SRQ bit
private void enableSRQButton_Click(object sender, System.EventArgs e)
{
try
{ // Registering a handler for an event automatically enables that event.
mbSession.ServiceRequest += OnServiceRequest;
WriteToSession(commandTextBox.Text);
updateSRQControls(false);
updateWriteControls(true);
}
catch(Exception exp)
{
MessageBox.Show(exp.Message);
}
}
private void OnServiceRequest(object sender, VisaEventArgs e)
{
try
{
var mbs = (MessageBasedSession)sender;
StatusByteFlags sb = mbs.ReadStatusByte();
if ((sb & StatusByteFlags.MessageAvailable) != 0)
{
string textRead = mbs.RawIO.ReadString();
readTextBox.Text = InsertCommonEscapeSequences(textRead);
}
else
{
MessageBox.Show("MAV in status register is not set, which means that message is not available. Make sure the command to enable SRQ is correct, and the instrument is 488.2 compatible.");
}
}
catch(Exception exp)
{
MessageBox.Show(exp.Message);
}
}
I then had to look into what an SRQ bit was. I found a useful page by NI that gave me a good grasp on how this works at a fundamental level. Skip about 1/4 down to the section titled, "IEEE 488.2 Status Register Overview". The rest was about LabView setup which wasn't helpful. I then found a page by Rhode&Schwarz that really helped me understand all the approaches to this and how to set things up.
I set up my own simple windows forms app to test this out.
private void ConnectToResourceButton_Click(object sender, EventArgs e)
{
try
{
using (ResourceManager resourceManager = new ResourceManager())
{
usbSession = (UsbSession)resourceManager.Open(this.ResourcesListBox.SelectedItem.ToString());
// Enable the Message Available bit
usbSession.FormattedIO.WriteLine("*SRE 16");
usbSession.ServiceRequest += UsbSession_ServiceRequest;
}
}
catch (Exception ex)
{
this.richTextBox1.AppendText($"Failed to connect to resource. {ex.Message}\r\n");
}
}
private void UsbSession_ServiceRequest(object sender, Ivi.Visa.VisaEventArgs e)
{
try
{
Ivi.Visa.StatusByteFlags statusByteFlags = usbSession.ReadStatusByte();
if ((statusByteFlags & Ivi.Visa.StatusByteFlags.MessageAvailable) > 0)
{
string s = usbSession.FormattedIO.ReadLine();
this.richTextBox1.AppendText(s);
}
}
catch (Exception ex)
{
this.richTextBox1.AppendText($"Service Request Error: {ex.Message}");
}
}
This should have worked. Nothing. I tried enabling events and polling for it instead.
private void ConnectToResourceButton_Click(object sender, EventArgs e)
{
try
{
using (ResourceManager resourceManager = new ResourceManager())
{
usbSession = (UsbSession)resourceManager.Open(this.ResourcesListBox.SelectedItem.ToString());
// Enable the Message Available bit
usbSession.FormattedIO.WriteLine("*SRE 16");
usbSession.EnableEvent(Ivi.Visa.EventType.ServiceRequest);
Task.Run(() => serviceRequestPoller());
}
}
catch (Exception ex)
{
this.richTextBox1.AppendText($"Failed to connect to resource. {ex.Message}\r\n");
}
}
private void serviceRequestPoller()
{
while (true)
{
try
{
// Will throw exception if no message received within timeout period of 1000 mS
usbSession.WaitOnEvent(Ivi.Visa.EventType.ServiceRequest, 1000);
Ivi.Visa.StatusByteFlags statusByteFlags = usbSession.ReadStatusByte();
if ((statusByteFlags & Ivi.Visa.StatusByteFlags.MessageAvailable) > 0)
{
string s = usbSession.FormattedIO.ReadLine();
this.richTextBox1.AppendText(s);
}
string s = usbSession.FormattedIO.ReadLine();
this.richTextBox1.AppendText(s);
}
catch (Exception ex)
{
this.richTextBox1.AppendText($"Service Request Error: {ex.Message}");
}
}
}
Nothing. I got no response. Only manual querying of the status register worked. However, the response would be received in the same receive queue as the message I would be waiting for. That defeated the purpose. So I despaired.
Until I thought to try another USBTMC instrument in the office. Everthing worked. The event based method without polling that I first showed worked flawlessly. Just as a word of warning, Rigol's DS4024 Status Register request via NI Visa does not work on at least FW v0.3.2.2. I grabbed a BK Precision variable load and things worked just fine.
At the end of the day I'm really happy I worked this out and got event based message reception working. I am left with two frustrations. Rigol for their faulty FW, but mostly for NI having basically no RECENT and COMPILABLE tutorials for working with NI Visa .NET. Even the documentation is just class and namespace definitions. It's very hard to find anything that says what any of these items do. Am I missing some great resource somewhere? I am not using LabView. I am building and writing all of my applications on Windows Forms Apps in Visual Studio.