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?