Problem Overview
The host-side IVI-C driver family shipped for the Keysight 53210A, 53220A, and 53230A RF frequency counters (driver family name ag532xx) contains a defect in the internal callback ag532xx_WaitForOPCCallback. The user-facing attribute AG532XX_ATTR_OPC_TIMEOUT is read from the IVI attribute store, but its millisecond value is never pushed into the underlying VISA session as VI_ATTR_TMO_VALUE before the *OPC? query is transmitted. The Operation Complete poll therefore always races against the default VISA I/O timeout (typically 2000 ms) regardless of how the caller has configured AG532XX_ATTR_OPC_TIMEOUT.
Observable symptoms:
-
*OPC?returnsVI_ERROR_TMO(0xBFFF0015) on long acquisitions even whenAG532XX_ATTR_OPC_TIMEOUTis set to 30 s or higher. - Intermittent
IVI_ERROR_CANNOT_RECOVER(0xBFFA4000) errors during burst or continuous measurement modes. - Inconsistent behavior across GPIB, USB, and LAN sessions that share the same driver instance, because the underlying VISA timeout differs by transport.
- False-positive success returns where
viQueryftimes out but the calling wrapper ignores the failure.
ag532xx.c). The defect is independent of instrument firmware revision; rebuilding the driver is sufficient.Affected Hardware and Driver Builds
| Instrument Model | Driver Builds Affected | Resolution |
|---|---|---|
| 53210A | All builds prior to the OPC-timeout patch release | Rebuild from patched source or upgrade to the post-patch installer |
| 53220A | All builds prior to the OPC-timeout patch release | Rebuild from patched source or upgrade to the post-patch installer |
| 53230A | All builds prior to the OPC-timeout patch release | Rebuild from patched source or upgrade to the post-patch installer |
The 53200A and 53200B entry-level counters use a separate driver family (ag53200) and are not affected by this defect.
Root Cause Analysis
The IVI driver architecture separates two distinct timeout domains that the buggy callback fails to bridge:
-
IVI attribute layer:
AG532XX_ATTR_OPC_TIMEOUTis the user-facing knob expressed in milliseconds. It is stored in the driver's per-session attribute table and accessible throughIvi_GetAttributeViInt32. -
VISA I/O layer:
VI_ATTR_TMO_VALUEcontrols how longviRead,viQueryf, andviScanfblock before returningVI_ERROR_TMO.
In the buggy implementation, only the IVI attribute is consulted. The VISA session timeout is left at its default (2000 ms, or whatever the application set during session init). When the instrument takes longer than the VISA timeout to assert the Operation Complete bit, viQueryf aborts before opcDone is populated. The function then returns success by coincidence because opcDone retains its stack-initialized value of VI_FALSE, masking the failure downstream in the calling IviWaitForOperationComplete wrapper.
The IVI specification requires that wrapper functions interacting with the instrument respect attribute-based timeout overrides. WaitForOPCCallback is registered during Ivi_Init and invoked by IviWaitForOperationComplete whenever the application calls any of the synchronization primitives such as ag532xx_Abort, ag532xx_Initiate, or ag532xx_MeasureFrequency.
Technical Background: IVI, VISA, and SCPI
The driver stack follows the standard IVI-C specification layered atop NI-VISA or compatible VISA implementations such as Keysight IO Libraries. The *OPC? query is defined in section 4.1.1 of the SCPI 1999 standard: it returns 1 to the output queue only after all pending operations have completed. Because the response travels through the same I/O path as ordinary instrument commands, *OPC? inherits the VISA I/O timeout unless the driver explicitly overrides it for the duration of the poll.
The reference VISA tree used for development is the Keysight IO Libraries Suite, which exposes VI_ATTR_TMO_VALUE through both the 32-bit and 64-bit session interfaces.
The Fix
Replace the body of ag532xx_WaitForOPCCallback in ag532xx.c with the following source. The change saves the active VISA timeout, applies the OPC timeout for the duration of the *OPC? query, and restores the original value to avoid side effects on subsequent VISA calls.
static ViStatus _VI_FUNC ag532xx_WaitForOPCCallback (ViSession vi, ViSession io)
{
ViStatus error = VI_SUCCESS;
ViInt32 opcTimeout, oldVISATimeout;
ViBoolean opcDone = VI_FALSE;
checkErr( Ivi_GetAttributeViInt32 (vi, VI_NULL,
AG532XX_ATTR_OPC_TIMEOUT,
0, &opcTimeout) );
viCheckErr( viGetAttribute (io, VI_ATTR_TMO_VALUE, &oldVISATimeout) );
viCheckErr( viSetAttribute (io, VI_ATTR_TMO_VALUE, opcTimeout) );
viCheckErr( viQueryf(io, "*OPC?", "%hd", &opcDone) );
viCheckErr( viSetAttribute (io, VI_ATTR_TMO_VALUE, oldVISATimeout) );
Error:
viDiscardEvents (io, VI_EVENT_SERVICE_REQ, VI_QUEUE);
return error;
}
The local oldVISATimeout capture is critical. Without it, a user-supplied session timeout configured by viSetAttribute(io, VI_ATTR_TMO_VALUE, ...) prior to ag532xx_init would be silently overwritten on every synchronization call, breaking subsequent application-level reads.
Step-by-Step Application
- Locate the IVI driver source tree. The default Windows install path for the Keysight 53200 series driver is
C:\Program Files\IVI Foundation\IVI\Drivers\ag532xx\ag532xx.c. - Back up the original
ag532xx.cfile. - Apply the code change shown above using a patch utility or manual edit.
- Recompile the driver using the IVI-C reference compiler distributed with the Keysight IO Libraries Suite or the open IVI-C build environment.
- Regenerate the installer with the supplied
build_installer.bator equivalent packaging script. - Distribute the updated
.msi(or deploy the rebuilt.dlland its 64-bit companion) to the target system. - Reboot any host application that statically loaded the old driver.
Verification
Execute the following programmatic check after installing the patched driver. The probe confirms that VI_ATTR_TMO_VALUE is temporarily overridden inside the callback while the underlying session retains its configured value across normal calls.
ViSession vi, io;
ViInt32 appliedTimeout;
ViReal64 measuredFreq;
const ViInt32 opcTimeoutMs = 30000;
ag532xx_InitWithOptions ("53230A",
VI_FALSE, VI_FALSE,
"Simulate=0,RangeCheck=1,QueryInstrStatus=1,Cache=1",
&vi);
io = Ivi_IOSession (vi);
ag532xx_SetAttributeViInt32 (vi, "",
AG532XX_ATTR_OPC_TIMEOUT,
opcTimeoutMs);
ag532xx_Initiate (vi);
ag532xx_MeasureFrequency (vi, 100000, &measuredFreq);
/* Inside WaitForOPCCallback the VISA timeout is now 30000 ms */
viGetAttribute (io, VI_ATTR_TMO_VALUE, &appliedTimeout);
/* appliedTimeout reflects the post-restore value, not opcTimeoutMs */
ag532xx_close (vi);
For manual confirmation, open Keysight Connection Expert, navigate to the 53230A instrument, and issue *OPC? interactively with the patched driver loaded. Requests exceeding 2 s but within the configured AG532XX_ATTR_OPC_TIMEOUT must no longer return VI_ERROR_TMO.
Verification Matrix
| Test | Expected Result | Pass Criterion |
|---|---|---|
| Long measurement with OPC timeout = 30 s | Driver returns success | No VI_ERROR_TMO logged |
| Pre-set VISA timeout = 5000 ms preserved across calls | Session timeout unchanged after *OPC?
|
Post-restore read equals 5000 ms |
| Forced instrument hang (clear status, no OPC) | Driver returns IVI_ERROR_OPERATION_NOT_COMPLETE
|
Caller sees error, not silent success |
| GPIB, USB, and LAN sessions in same process | Each session uses its own timeout | No cross-session leakage of VI_ATTR_TMO_VALUE
|
VISA and IVI Error Code Reference
| Constant | Hex | Meaning |
|---|---|---|
VI_SUCCESS |
0x00000000 | Operation completed without error |
VI_ERROR_TMO |
0xBFFF0015 | Timeout expired before operation completed |
VI_ERROR_INV_SESSION |
0xBFFF000E | Given session handle is not valid |
IVI_ERROR_CANNOT_RECOVER |
0xBFFA4000 | Driver could not recover from a fatal error |
IVI_ERROR_INVALID_VALUE |
0xBFFA4001 | Attribute value is out of the supported range |
IVI_ERROR_OPERATION_NOT_COMPLETE |
0xBFFA400F | OPC query returned before completion flag |
Related Considerations
-
Session sharing: When two threads share a single VISA session and call
ag532xx_WaitForOPCCallbackconcurrently, the save/override/restore pattern is not atomic. Wrap the callback registration in an external mutex if your application uses multiple worker threads. -
Range checking: The default range for
AG532XX_ATTR_OPC_TIMEOUTis 1 ms to 60000 ms. Values outside this range must be rejected whenRangeCheck=1is set in the driver session options. -
Simulate mode: When
Simulate=1is passed toag532xx_InitWithOptions, the callback is bypassed entirely; the patch has no effect in simulation. -
GPIB vs LAN latency: LAN-connected instruments can exhibit 5–20 ms of TCP round-trip overhead per poll iteration. Configure
AG532XX_ATTR_OPC_TIMEOUTto at least 5× the expected worst-case single-shot measurement time to avoid spurious timeouts on burst measurements. -
Event queue discipline: The trailing
viDiscardEvents(io, VI_EVENT_SERVICE_REQ, VI_QUEUE)clears any pending IEEE 488.2 service request events so that subsequent status byte polling does not observe stale notifications.
Alternative Workarounds
If rebuilding the driver is not feasible, two application-level patterns restore correct behavior without touching the source:
- Pre-set VISA timeout before IVI init:
viSetAttribute(io, VI_ATTR_TMO_VALUE, opcTimeoutMs);
ag532xx_SetAttributeViInt32(vi, "",
AG532XX_ATTR_OPC_TIMEOUT,
opcTimeoutMs);
-
Disable QueryInstrStatus in the session options string: The driver skips the
WaitForOPCCallbackpath entirely and relies on synchronous command execution. This removes the asynchronous polling benefit but eliminates the timeout race.
Adjacent Driver Audit Template
Use the following checklist to inspect other IVI drivers in the same family or from the same vendor for the same defect pattern:
- Does
<prefix>_WaitForOPCCallbackread an OPC timeout attribute? - Does it call
viSetAttribute(io, VI_ATTR_TMO_VALUE, ...)with that value before*OPC?? - Does it save and restore the original
VI_ATTR_TMO_VALUE? - Does it call
viDiscardEventson the IEEE 488.2 service request queue?
If any check fails, apply the same save/override/restore template demonstrated in the fix section above.
What does AG532XX_ATTR_OPC_TIMEOUT control?
It defines the maximum time in milliseconds that the driver waits for the instrument to assert the Operation Complete bit after a command is issued. The value must be applied to the VISA I/O timeout before any *OPC? query, otherwise the default 2000 ms VISA timeout overrides the user setting.
Why does *OPC? appear to succeed even when it times out?
The callback allocates opcDone on the stack and initializes it to VI_FALSE. If viQueryf aborts with VI_ERROR_TMO, the function returns the error but opcDone retains its initialized value. Downstream wrappers may interpret the absent success signal incorrectly and retry silently.
Does this affect Keysight 53200A or 53200B models?
No. The 53200A and 53200B entry-level counters use a different driver family (ag53200). The defect is confined to the 53210A, 53220A, and 53230A driver family (ag532xx).
Can this patch template be applied to other IVI drivers?
Yes. The save/override/restore pattern is broadly applicable to any IVI driver whose OPC callback reads an attribute timeout but fails to push it into the VISA layer. Auditing other driver callbacks against this template is recommended for fleet-wide reliability.
Will the fix change behavior when Simulate=1 is set?
No. In simulation mode the callback path is bypassed and *OPC? is handled entirely by the simulation engine. The patched code is inert in that mode and introduces no behavioral change.