This manual provides a single reference to the functionality exposed by the AIOWDM driver package. AIOWDM supports PCI-based plug-and-play devices, including direct register access, watchdog timer control, change-of-state IRQ handling, DAC control, and board discovery.
All supported PCI and PCIe form factors other than serial boards use AIOWDM. This includes conventional PCI, PCI Express, mPCIe, M.2, PCI-104, PC/104+, and related form factors.
The manual is organized by function family. Functions marked Advanced are normally needed only for specialized applications. Deprecated APIs are hidden initially and can be displayed using the control above the table of contents.
General Information
Calling Conventions and Header Files
AIOWDM functions are exported in three forms: underscored with the cdecl calling convention, undecorated with the stdcall calling convention, and undecorated with the cdecl calling convention. The appropriate form depends on the language and import mechanism being used.
Language-specific declarations are supplied in files such as AIOWDM.h, AIOWDM.cs, and AIOWDM.vb. They are installed below C:\Users\Public\Documents\ACCES\{package name}\Win32\Driver.SRC\AIOWDM\Headers\. Use those declarations rather than recreating pointer types and calling conventions from this manual.
CardNum and Multiple-Card Systems
CardNum is a zero-based index into the list of AIOWDM devices detected in the system. In a system with one AIOWDM card, CardNum is normally zero.
Applications that can encounter multiple AIOWDM cards should call GetNumCards() and QueryCardInfo() during initialization. Once the correct CardNum has been selected, the remaining API calls are used in the same way as they are in a single-card system.
Accessing Registers
RelInPort*() / RelOutPort*()
Purpose
Read or write a register using a card-relative offset. Every function takes CardNum first and a register offset second. Output functions take the value to write as the final argument.
The RelInPort* family returns a byte-, word-, or 32-bit value. The RelOutPort* family writes the corresponding width. These operations are the plug-and-play equivalents of processor port-I/O instructions and the Windows kernel port-access macros.
The register offset relative to the selected card's base address.
Value
The byte, word, or 32-bit value to write.
Returns
Read functions return the register value. All functions can return the sentinel 0xAA55 when the underlying AIOWDM.SYS driver is not installed or cannot be opened correctly.
Notes
Because 0xAA55 is a valid word or 32-bit value, perform one byte-sized read from a safe register during application initialization. A byte read cannot normally produce a 16-bit 0xAA55 value, making it an unambiguous driver check.
Example
value = RelInPort(0, 2);
value = RelInPortB(1, 12);
RelOutPortL(0, 0, value);
The absolute-address APIs below are deprecated. They were used by legacy applications that located cards through PCIFind, registry data, or a separate non-plug-and-play driver. New and migrated applications should use the card-relative RelInPort* and RelOutPort* APIs.
InPort*() / OutPort*()
Purpose
Access an absolute I/O-space address. These functions do not take CardNum; the application must discover and track the card's plug-and-play-assigned base address itself.
AIOWDM's relative register functions eliminate the need for PCIFind, NTioPCI.SYS, legacy registry arrays such as PCI_COMMON_CONFIG, and application-side base-address arithmetic.
value = InPortL(CardBaseAddress + RegisterOffset);
Migration Procedure
For a single-card application, migrate the old absolute-address code as follows:
Locate initialization code that calls QueryCardInfo() for a base address or reads HKLM\Software\PCIFind\Parameters.
Remove the obsolete base-address discovery code.
Replace InPort* and OutPort* calls with the corresponding RelInPort* and RelOutPort* calls.
Replace BASE + offset with 0, offset. In a multiple-card application, replace zero with the selected CardNum variable.
u32bData = InPortL(BASE + 3);
// After changing to the relative API:
u32bData = RelInPortL(0, 3);
// Multiple-card application:
u32bData = RelInPortL(CardNumVariable, 3);
Operating Analog Outputs (DACs)
The DAC_* functions operate supported PCI and PCIe DAC-output boards, from the PCIe-DA16-16 through the PCI-DA12-2 family.
These boards power up or reset with output voltage restricted. Before enabling normal output, write known values to the DACs, select the desired simultaneous or asynchronous update mode, issue an update if needed, and then clear voltage-restrict mode.
Unlike many older AIOWDM functions, these DAC APIs return Win32 error codes directly. ERROR_SUCCESS (zero) means success; any nonzero value is an error code.
DAC Information and Configuration
DAC_GetNumDacs()
Purpose
Retrieve the number of DAC channels on the selected card so an application can adapt to different models.
A Win32 error code. ERROR_SUCCESS (zero) means success.
DAC_ConfigureVoltageRestrictMode()
Purpose
Enable or disable the board's voltage-restrict safety mode. Pass false to permit normal DAC output after known output values and update mode have been configured.
Nonzero updates all DAC outputs to their last commanded values.
bSimultaneous
Nonzero selects simultaneous mode; zero selects asynchronous mode.
Returns
A Win32 error code. ERROR_SUCCESS (zero) means success.
Notes
The native DLL parameter order is bUpdate, then bSimultaneous. Some older C# declarations and manual text reversed those two names.
DAC_GetRange() / DAC_GetRanges()
Purpose
Retrieve the configured range for one DAC or all DACs. When supported, the DLL reads the range selected by the board's DIP switches.
For boards that cannot report their switch-selected range, the value comes from DLL state previously established with DAC_SetRange() or DAC_SetRanges().
A Win32 error code. ERROR_SUCCESS (zero) means success.
DAC_ReloadCalibrationData()
Purpose
Refresh the DLL's shadow copy of EEPROM calibration data after range-switch or EEPROM contents are changed while the process is running. This is primarily a factory or maintenance operation.
Signature
UInt32 DAC_ReloadCalibrationData(UInt32 CardNum);
Returns
A Win32 error code. ERROR_SUCCESS (zero) means success.
DAC_GetCalibrationData()
Purpose
Read the EEPROM-derived calibration data for all supported ranges and DACs. This function is primarily intended for factory and calibration utilities.
A Win32 error code. ERROR_SUCCESS (zero) means success.
DAC_WriteCalibrationData()
Purpose
Update the DLL's shadow copy of per-range, per-DAC calibration data and optionally write it to the board's EEPROM. This function is intended for factory and calibration utilities.
A Win32 error code. ERROR_SUCCESS (zero) means success.
DAC_Output() / DAC_Outputs()
Purpose
Output one or more floating-point voltage or current values. The DLL converts each value to counts using the configured range and resolution, and applies software calibration when enabled.
A Win32 error code. ERROR_SUCCESS (zero) means success.
Using Digital Integration Features
Many models support advanced digital input and output features, including pulse measurement and generation, edge counting, and IRQ generation. See the Digital Integration Features Register Reference Manual for the register model and API details.
Handling IRQs
WaitForIRQ()
Purpose
Block the calling thread until the selected card generates an IRQ, the request is aborted, or an error occurs. It is intended for a dedicated IRQ-service thread.
Signature
UInt32 WaitForIRQ(Int32 CardNum);
Arguments
CardNum
The card whose IRQ is being awaited.
Returns
Nonzero when the function returns because an IRQ occurred. Zero means the wait was aborted or failed.
After a zero return, GetLastError() returns ERROR_OPERATION_ABORTED for an aborted request and ERROR_INVALID_FUNCTION when another thread is already waiting on that card.
AbortRequest()
Purpose
Cancel the pending request begun by WaitForIRQ(), COSWaitForIRQ(), or the internal wait used by WDGHandleIRQ().
Signature
UInt32 AbortRequest(Int32 CardNum);
Returns
Nonzero on success; zero when there was no pending request to abort or the operation failed.
Notes
Call AbortRequest() or CloseCard() before terminating the thread or process that owns a pending wait. A wait left in the driver after its user-mode thread has disappeared can resume into invalid process state and crash Windows.
If an application has already crashed while a wait was pending, do not call AbortRequest() from another process. Disable all AIOWDM devices in Device Manager and then re-enable them to clear the stale request.
CloseCard()
Purpose
Abort pending IRQ activity and close the DLL handle for the selected card. Use it before changing or reloading card-number assignments and before terminating a thread that owns an IRQ wait.
Signature
UInt32 CloseCard(Int32 CardNum);
Returns
Nonzero on success; zero if there was no open handle or the close failed.
Notes
Windows closes ordinary handles when the DLL unloads, but that is too late to safely cancel a wait owned by a thread that has already exited.
Handling Change-of-State IRQs (8255 DIO Cards)
COSWaitForIRQ()
Purpose
Wait for an IRQ and immediately read the card's PPI data after the IRQ. This is designed for the PCI-DIO-24S, PCI-DIO-48S, IOD24S, and IOD48S.
Do not use this function on an unrelated card merely because it supports IRQs; reads can have side effects on some hardware. Verify the device ID with QueryCardInfo() first.
The number of PPIs to read. The PCI-DIO-24S has one; the PCI-DIO-48S has two. A PCI-DIO-48S may be read with one when the second PPI is not needed.
pData
A buffer with at least three bytes per PPI.
Notes
In Visual Basic, pass the first element of a byte array sized to at least three bytes per PPI. For two PPIs, for example: Dim Data(0 To 5) As Byte, then COSWaitForIRQ(CardNum, 2, Data(0)).
Watchdog Timer and Computer Status Monitor Functions
These functions are designed for supported watchdog boards, especially the PCI-WDG-CSM family. Verify the card's device ID before calling a watchdog-specific function.
WDGInit()
Purpose
Prepare the selected watchdog card for subsequent WDG* calls such as WDGPet() and WDGHandleIRQ().
Signature
UInt32 WDGInit(Int32 CardNum);
Returns
Nonzero on success; zero on failure.
WDGHandleIRQ()
Purpose
Configure how the next watchdog IRQ is handled. The card must first be prepared with WDGInit().
Nonzero on success; zero on failure. Values greater than 5 are not supported.
Action
Behavior
0
Ignore. Allow the watchdog circuit to perform its configured hard reset when the timer expires.
1
Disable. Disable the watchdog when its IRQ occurs.
2
Soft shutdown and restart. Change the watchdog timeout to 90 seconds, then begin an ordinary Windows shutdown. The later hard reset provides a fallback.
3
Disable and soft restart. Disable the watchdog, then begin an ordinary Windows restart.
4
Mostly-soft shutdown and restart. Change the watchdog timeout to 90 seconds and begin a shutdown that allows a limited save interval but cannot be cancelled. The later hard reset provides a fallback.
5
Disable and mostly-soft restart. Disable the watchdog, then begin the non-cancellable, limited-save restart sequence.
WDGSetTimeout()
Purpose
Stop the watchdog timer, configure its timeout, and prepare it for WDGStart(). The card must first be initialized with WDGInit().
Zero disables the ISA buzzer or prevents the PCI board from asserting reset. A value greater than zero and no more than 1.0 enables the buzzer or selects an infinite PCI reset duration. Larger values request a finite PCI reset duration.
MHzClockRate
The board clock in MHz.
Returns
The finite reset duration achieved. Returns zero for failure, buzzer-only operation, disabled reset, or infinite reset duration.
WDGPet()
Purpose
Reset the watchdog timers before they expire. The card must first be initialized with WDGInit().
Signature
UInt32 WDGPet(Int32 CardNum);
Returns
Nonzero on success; zero on failure.
WDGReadTemp()
Purpose
Read the watchdog board's temperature sensor in degrees Fahrenheit.
Signature
double WDGReadTemp(Int32 CardNum);
Returns
The measured temperature. A board without a temperature sensor reports 194.0 °F; failure returns 0.0 °F. A valid reading is not expected below 7.0 °F.
WDGReadStatus()
Purpose
Read the watchdog status byte at base offset 4. This read also enables watchdog IRQs, although IRQs remain ignored unless WDGHandleIRQ() has configured handling.
Signature
UInt32 WDGReadStatus(Int32 CardNum);
Returns
A status byte from 0x00 through 0xFF on success; a value greater than 0xFF on failure. The bit definitions are documented in the board manual.
WDGStart()
Purpose
Start watchdog timing after the timeout and reset behavior have been configured.
Signature
UInt32 WDGStart(Int32 CardNum);
Returns
Nonzero on success; zero on failure.
WDGStop()
Purpose
Stop watchdog timing.
Signature
UInt32 WDGStop(Int32 CardNum);
Returns
Nonzero on success; zero on failure.
EmergencyReboot()
Purpose
Begin a mostly-soft restart that gives Windows and applications a limited opportunity to save data but does not allow the restart to be cancelled.
Signature
UInt32 EmergencyReboot(void);
Returns
Nonzero on success; zero on failure, commonly because the process lacks permission to restart the system.
Plug-and-Play — Detecting and Identifying Hardware
Applications that may encounter more than one AIOWDM device should discover cards at runtime. GetNumCards() supplies the list size and QueryCardInfo() identifies each entry. Subsequent API calls use the selected zero-based CardNum.
Card Discovery
GetNumCards()
Purpose
Return the number of AIOWDM cards currently present in the DLL's card list. Valid card numbers are zero through one less than the returned count.
Signature
Int32 GetNumCards(void);
Returns
The number of detected cards.
QueryCardInfo()
Purpose
Retrieve the device ID, optional absolute base address, and friendly name for the selected card. Use this function to identify which model occupies a given CardNum.
Receives the card's device ID. For PCI cards this is the PCI device ID. May be null when not needed.
pBase
Receives the absolute I/O base address. May be null. Modern applications using RelInPort* and RelOutPort* normally should pass null.
pNameSize
On entry, the friendly-name buffer size. On exit, receives the required size including the terminating null. May be null when the name is not needed.
pName
Receives the Windows ANSI friendly name. If the supplied size is zero or too small, the buffer is not modified.
Returns
Nonzero on success; zero on failure, commonly because CardNum is invalid or card information could not be read.
Card Number Assignment
These functions are intended for setup and configuration utilities that need to inspect or change the visible CardNum assigned to installed boards. Ordinary acquisition applications normally only need GetNumCards() and QueryCardInfo().
AIOWDM card numbers are zero-based. By default, detected cards are ordered by PCI bus, device, and function. The assignment API swaps two visible card numbers and persists that preference; it does not move hardware or change Windows device IDs or PCI location values.
Call CloseCard() for every open card before calling SwapCards(), ResetCardOrder(), or ReloadCardList(). The configuration process may need to run elevated because the persisted order is stored in Windows device-interface registry storage.
Error
Typical meaning
ERROR_INVALID_PARAMETER
An invalid card number or output pointer was supplied.
ERROR_NOT_FOUND
The requested card or its device-interface registry storage could not be found.
ERROR_BUSY
A card is open or an IRQ wait/callback prevents the card list from being changed safely.
ERROR_ACCESS_DENIED
Windows denied permission to update the persisted order.
QueryCardLocation()
Purpose
Retrieve the PCI bus, device, and function numbers associated with a visible CardNum. Pair this with QueryCardInfo() when displaying a multi-card system to a user.
Exchange the visible card numbers assigned to two installed AIOWDM cards and persist the new order.
The calling process sees the new order immediately. Later processes and reboots use it while Windows continues to identify the same installed device/interface instances. The API is deliberately swap-based so the visible list remains compact and contains no gaps.
Signature
UInt32 SwapCards(Int32 CardNumA, Int32 CardNumB);
Arguments
CardNumA
The first visible card number.
CardNumB
The second visible card number.
Returns
Nonzero on success; zero on failure.
Example
// Cards 0 and 2 exchange positions.
SwapCards(0, 2);
ResetCardOrder()
Purpose
Delete all persisted card-order values and restore the DLL's default PCI bus/device/function ordering. The implementation reloads the card list in the calling process after a successful reset.
Signature
UInt32 ResetCardOrder(void);
Returns
Nonzero on success; zero on failure.
ReloadCardList()
Purpose
Rebuild the DLL's current card list from installed devices and persisted order values. Use it after hardware changes or after another process changes card order.
Signature
UInt32 ReloadCardList(void);
Returns
Nonzero on success; zero on failure. The function reports ERROR_BUSY when any card is open or an IRQ wait/callback is active.
Recommended Card-Number Assignment Workflow
Start the setup utility elevated when system policy requires administrative rights for device-interface registry writes.
Call GetNumCards().
For each card, call QueryCardInfo() and QueryCardLocation(), then display the model, device ID, and PCI bus/device/function location.
Ask the user which two visible card numbers should be exchanged.
Call CloseCard() for every card that may be open in the process.
Call SwapCards(cardA, cardB).
Display the card list and locations again to confirm the new order.