I am developing firmware for a USB instrument, and using NI-VISA extensively to test and debug it. I would like to be able to read the data packet that comes on the Interrupt-IN endpoint during a USBTMC-USB488.2 service request (SRQ). I think the firmware is doing the right thing because this code works:
ViSession defaultRM = VI_NULL, instr = VI_NULL;
// clear status; set OPC (operation complete) in event status enable;
// set ESB (event status bit) in Status Byte Enable Register; start an
// overlapped command; and generate a service request (SRQ) when
// the operation completes.
ViByte buf[] = "*CLS;*ESE 1;*SRE 32;:SYST:ARR:CLK 2304;*OPC";
ViUInt32 cnt;
ViUInt16 STB;
viOpenDefaultRM(&defaultRM);
viOpen(defaultRM, "USB0::0x0000::0x0001::0::INSTR", VI_NULL, VI_NULL, &instr);
// Service request events go into the standard event queue
viEnableEvent(instr, VI_EVENT_SERVICE_REQ, VI_QUEUE, VI_NULL);
// start an overlapped command that takes some time to complete, and wait for the
// service request that indicates it is finished.
viWrite(instr, buf, sizeof(buf)-1, &cnt);
viWaitOnEvent(instr, VI_EVENT_SERVICE_REQ, VI_TMO_INFINITE, VI_NULL, VI_NULL);
// When you receive a VI_EVENT_SERVICE_REQ on an INSTR session, you must call
// viReadSTB() to guarantee delivery of future service request events on the
// given session.
viReadSTB(instr, &STB);
viWaitOnEvent gets the event, and the status byte I read has the right flags set (SRQ and ESB). Since the status byte value is transmitted from the USB device to the host in a packet from the Interrupt-IN endpoint, it seems like it must be getting that packet.
I would like to see that packet. But various things I have tried to get it from NI-VISA have so far failed. For example, I tried installing this callback handler:
static ViStatus _VI_FUNCH interrupt_in_hndlr(ViSession vi, ViEventType typ, ViEvent evt, ViAddr userHandle)
{
HANDLE interrupt_in_event = userHandle;
ViUInt16 size;
VI_ERROR(viGetAttribute(evt, VI_ATTR_USB_RECV_INTR_SIZE, &size));
if (typ != VI_EVENT_USB_INTR)
return VI_ERROR_INV_EVENT;
if (size > 0) {
ViPByte buf = new ViByte[size];
VI_ERROR(viGetAttribute(evt, VI_ATTR_USB_RECV_INTR_DATA, buf));
printf("Interrupt-IN data =");
for (int i=0; i<size; ++i)
printf(" %02x", buf[i]);
printf("\n");
} else {
printf("No Interrupt-IN data!\n");
}
SYSERR(SetEvent(interrupt_in_event), FALSE);
return VI_SUCCESS;
}
with this code
HANDLE interrupt_in_event;
SYSERR(interrupt_in_event = CreateEvent(NULL, TRUE, FALSE, NULL), NULL);
// Install a handler for USB Interrupt-IN events
VI_ERROR(viInstallHandler(instr, VI_EVENT_USB_INTR, interrupt_in_hndlr, interrupt_in_event));
VI_ERROR(viEnableEvent(instr, VI_EVENT_USB_INTR, VI_HNDLR, VI_NULL));
and it never gets called. I tried putting those events on the standard event queue, and the call to viEnableEvent fails. I tried to open the ::RAW device instead of the ::INSTR device, and that fails.
Can anyone lend me a clue?