# Universal Library Language Interface

The interface to all languages is a set of methods or function calls and enumerations orconstants . The interface is nearly identical for each language. Refer to the sections below, and especially to the example programs for each language. This topic is brief with respect to details of language use and syntax. Review the example programs for more detailed information. The example programs, or a link to the example programs for each language, are located in the installation directory.

Select a link below for more information.

- Universal Library for Windows
- Universal Library for .NET
- Python for Windows

## Universal Library for Windows

### Function Arguments

Each library function takes a list of arguments and most return an error code. Some functions also return data via their arguments. For example, one of the arguments for cbAIn() is the name of a variable in which the analog input value will be stored. All function arguments that return data are listed in the "Returns:" section of the function description.

### Constants

Many functions take arguments that must be set to one of a small number of choices. These choices are all given symbolic constant names. For example, cbLogGetPreferences() takes an argument called TimeFormat that must be set to either TIMEFORMAT_12HOUR or TIMEFORMAT_24HOUR. These constant names are defined and assigned a value in the "header" file for each language. Although it is possible to use the numbers rather than the symbolic constant names, we strongly recommend that you use the names. This will make your programs more readable and more compatible with future versions of the library. The numbers may change in future versions but the symbolic names will always remain the same.

### Options Arguments

Some library functions have an argument called Options. The option argument is used to turn on and off various optional features associated with the function. If you set Options = 0, then the function will set all of these options to the default value, or off.

Some options can have an alternative value, such as BACKGROUND and FOREGROUND. If an option can have more than one value, one of the values is designated as the default.

Individual options can be turned on by adding them to the Options argument. For example, Options = BACKGROUND will turn on the "background execution" feature. Options = BACKGROUND+CONTINUOUS will select both the "background execution" and the "continuous execution" feature.

### Error Handling

Most library functions return an error code. If no errors occurred during a library call, 0 (or NOERRORS) is returned as the error code; otherwise, one of the codes listed in Error Codes is returned.

If a non-zero error code is returned, you can use cbGetErrMsg() to convert the error code to a specific error message. As an alternative to checking the error code after each function call, you can turn on the library's internal error handling with cbErrHandling().

#### 16-bit Values using a Signed Integer Data Type

When using functions that require 16-bit values, the data is normally in the range 0 to 65,535. However, some programming languages, such as Visual Basic®, only provide signed data types. When using signed integers, reading values above (32,767) can be confusing.

The number (32,767) is equivalent to (0111 1111 1111 1111) binary. The next increment (1000 0000 0000 0000) binary has a decimal value of (–32,768). The maximum value (1111 1111 1111 1111) binary translates to (-1) decimal. Keep this in mind if you are using languages that don't support unsigned integers.

There is additional information on this topic in the Universal Library Function Reference. Also, refer to the documentation supplied with your language compiler.

#### 32-bit Values using a Signed Long Data Type

When using functions that require 32-bit values, the data is normally in the range 0 to 4,294,967,295. However, some programming languages, such as Visual Basic®, only provide signed data types. When using signed integers, reading values above (2,147,483,647) can be confusing. The number (2,147,483,647) is equivalent to (0111 1111 1111 1111 1111 1111 1111 1111) binary. The next increment (1000 0000 0000 0000 0000 0000 0000 0000) binary has a decimal value of (–2,147,483,648). The maximum value (1111 1111 1111 1111 1111 1111 1111 1111) binary translates to (–1) decimal. Keep this in mind if you are using languages that don't support unsigned longs.

#### Visual Basic

To use the Universal Library with Visual Basic, include the Universal Library declaration file CBW.BAS file as a module in the project, or include it by reference inside Forms which call into the Universal Library. Once UL declarations are added to the project, call the library functions from the Form event handlers. CBW.BAS references CBW32.DLL to call Universal Library functions; this is accomplished with conditional compile statements.

For Visual Basic 6.0 and older, Windows memory buffers cannot be mapped onto arrays. As a consequence, the cbWinArrayToBuf() and cbWinBufToArray() functions must be used to copy data between arrays and Windows buffers.

Example:

Count = 100

MemHandle = cbWinBufAlloc (Count)

cbAInScan (......,MemHandle,...)

For i = 0 To Count

Print DataArray(i)

Next i

cbWinBufFree (MemHandle)

#### Visual C++

To use the Universal Library with MS Visual C++, include the Universal Library header file CBW.H in the C/C++ program, and add the library file CBW32.LIB to the library modules for linking to the CBW32.DLL.

## Universal Library for .NET

.Net languages such as C# and Visual Basic .Net are supported by simply adding a reference to MCCDAQ.DLL to your Visual Studio project. (Visual Studio 2005 or greater is required to run example programs.)

The Microsoft .NET platform provides a framework that allows for the development of Windows applications using a wide range of programming languages such as VB .NET, C#, managed C++, JScript, and any other language that is compliant with the .NET Common Language Runtime (CLR). The CLR is a multi-language execution environment.

The interface to the Universal Library consists of standard "C" functions. These functions are not CLR-compliant. Therefore, the Universal Library for .NET was developed. This library enables the various .NET programming languages to call into the Universal Library.

Note: Universal Library support for .NET requires that the Microsoft .NET Framework 2.0 be installed on the system before you install the Universal Library.

### MccDaq namespace

The MccDaq namespace is a naming scheme for grouping types into logical categories of related functionality. The namespace contains the classes and enumerated constants by which UL for .NET applications access the Universal Library data types and functions. The namespace provides an interface that exposes each Universal Library for .NET function as a member of a class with virtually the same parameters set as their UL counterparts.

When you develop a .NET application that uses the Universal Library, you add the MccDaq Namespace as a reference to your project. There are no header files in a .NET project.

### MccDaq classes

The Universal Library for .NET consists of a set of classes. For the most part, the methods within each class have a corresponding function in the standard UL. Each UL for .NET method has virtually the same parameter set as their UL counterparts. The MccDaq Namespace contains the following classes:

Class name | Description
MccBoard | Provides access to all of the methods for data acquisition and properties providing board information and configuration for a particular board.
ErrorInfo | Contains all of the members for storing and reporting error codes and messages. This class also includes error code enumerated constants, which define the error number and associated message that can be returned when you call a method.
MccService | Contains all of the members for calling utility UL functions.
cGlobalConfig | Contains all of the members for getting global board configuration information.
DataLogger | Contains all of the members for reading and converting binary log files.
DaqDeviceManager | Contains all of the members for discovering USB, Bluetooth, and Ethernet devices without using InstaCal.
DaqDeviceDescriptor | Contains all of the members for examining the descriptor information of a detected device.

The MccDaq namespace also contains the following secondary classes:

Class name | Description
cBoardConfig | Contains all of the members for setting and getting board-level configuration.
cCtrConfig | Contains all of the members for setting and getting the counter-level configuration of a board.
cDIOConfig | Contains all of the members for getting the digital configuration of a board.
cExpansionConfig | Contains all of the members for setting and getting expansion board configuration.

These secondary classes include methods that are accessible from properties of the MccBoard class.

The MccDaq assembly allows you to design Common Language Specification (CLS) –compliant programs. A CLS-compliant program contains functions that can be called from any existing or future language developed for the Microsoft .NET Framework. Using CLS-compliant data types ensures future compatibility.

### Board Number

In a .NET application, you can program multiple boards by creating an MccBoard class for each board installed.

Board0=new MccBoard(0)

Board1=new MccBoard(1)

Board2=new MccBoard(2)

The board number may be passed into the MccBoard class, which eliminates the need to include the board number as a parameter to the board methods.

### MccDaq Enumerated types

Instead of using constants such as BIP5VOLTS, the Universal Library for .NET uses enumerated types. An enumerated type take settings such as range types, scan options or digital port numbers, and puts them into logical groups.

When programming inside of Visual Studio .NET, the types that are available for a particular enumerated value display automatically when you type code. The example below lists MccDaq.ScanOptions enumerated values.

### Parameter data types

Many of the Universal Library for .NET methods are overloaded to provide for signed or unsigned data types as parameters. The AConvertData() function is shown below using both signed and unsigned data types.

VB .NET | Public Function AConvertData(ByVal numPoints As Integer, ByRef adData As Short, ByRef chanTags As Short) As MccDaq.ErrorInfo Member of MccDaq.MccBoard
| Public Function AConvertData(ByVal numPoints As Integer, ByRef adData As System.UInt16, ByRef chanTags As System.UInt16) As MccDaq.ErrorInfo Member of MccDaq.MccBoard
C# .NET | public MccDaq.ErrorInfo AConvertData (System.Int32 numPoints, System.Int16 adData, System.Int16 chanTags) Member of MccDaq.MccBoard
| public MccDaq.ErrorInfo AConvertData(System.Int32 numPoints, System.UInt16 adData, System.UInt16 chanTags) Member of MccDaq.MccBoard

For most data acquisition applications, unsigned data values are easier to manage. However, since Visual Basic (version 6 and earlier) does not support unsigned data types, it may be easier to port these programs to .NET if the signed (Int16) data types are used for the function parameters. For additional information on using signed data types, refer to 16-bit values using a signed integer data type.

The short (Int16) data type is CLS-compliant, supported in VB, and will be included in any future .NET language developed for the .NET Framework. Using CLS-compliant data types ensures future compatibility. Unsigned data types (UInt16) are not CLS-compliant, but are still supported by various .NET languages, such as C#.

### Error Handling

The return value for a UL for .NET method is an ErrorInfo() object that contains the number of the error that occurred as well as associated error message.

The example below shows how to perform error checking within a .NET aplication:

ULStat=Board0.AIn(Channel, Range, DataValue)

'check the numeric value of ULStat

If Not ULStat.Value = ErrorInfo.ErrorCode.NoErrors Then

'if there was an error, then display the error message

MsgBox ULStat.Message

EndIf

### Configuring a UL for .NET Project

Programming the Universal Library API is available through the various languages supported by the Microsoft .NET Framework. All .NET applications access the Universal Library (CBW32.DLL and CBW64.DLL) through the MccDaq .NET assembly (MCCDAQ.DLL). The MccDaq assembly provides an interface that exposes each Universal Library function that is callable from the .NET language.

The Universal Library for .NET is designed to provide the same "look and feel" as the Universal Library for Windows. This design makes it easier to port over existing data acquisition programs, and minimizes the learning curve for programmers familiar with the Universal Library API.

In the Universal Library for .NET, each function is exposed as a class method with virtually the same parameter set as their UL counterparts.

#### Referencing the MccDaq Namespace in a .NET Project

In a .NET application, there are no header files to include in your project. You define methods and constants by adding the MccDaq assembly, or Namespace, as a reference to your project. You access UL for .NET methods through a class that has the Universal Library as a member.

To add the MccDaq Namespace as a reference in a Visual Studio .NET project:

1. Start a new Visual Basic or C# project in Visual Studio .NET.
2. From the Visual Studio .NET Solution Explorer window, right-click on References and select Add Reference.
4. The Add Reference window appears.

3. From the .NET tab, select the MccDaq option from the displayed list of .NET assemblies and click on the OK button.
5. MccDaq appears under the References folder in the Solution Explorer window.

The MccDaq Namespace is now referenced by your Visual Studio .NET project.

## Python

The Measurement Computing Universal Library Python API for Windows is a wrapper around Universal Library functions, and can be imported into any integrated development environment (IDE) that supports Python, such as Eclipse (Neon and later) and Visual Studio (2015 and later). The UL for Python example programs can be run with Measurement Computing USB, Bluetooth, or Ethernet hardware.

##### Software and hardware requirements

- Measurement Computing InstaCal and Universal Library (current versions)
- Python versions 2.7, 3.4 and later
- Microsoft Windows 10/8/7, 32/64-bit
- Eclipse (Neon and later) and Visual Studio (2015 and later)
- Measurement Computing USB, Bluetooth, or Ethernet hardware

The main difference between the Python API and the UL for most other languages is how lists and arrays are used, how values are returned, and how errors are handled.

### Lists and Arrays

Python uses lists by default instead of arrays. If speed is required, however, C arrays are used to ensure that data is handled efficiently. Lists are created by simple assignment: my_list = []

Lists are dynamically sized, so users can add or remove items without defining a size. When performance is not a concern, a list can be passed directly to a function and Python will convert it to a c-type array. Examples of functions that do this include a_load_queue, d_out_array, and daq_in_scan (for config items such as chan_list, gain_list, and so on, but not the data).

When scanning a pointer to a C array, memhandle is created with win_buf_alloc() and passed to a_in_scan() and other scanning methods. The pointer returned from win_buf_alloc() can be cast to a ctypes array at any point. The cast works in the same way as a c-style cast, in that the pointer will be valid until win_buf_free() is called on memhandle:

array = ctypes.cast(memhandle, ctypes.POINTER(ctypes.c_ushort))

take care to call win_buf_free(), typically in the finally block of a try-finally clause, to prevent memory leaks.

Some functions require the user to allocate a c-type array, such as win_buf_to_array(). To create a c-type array of unsigned short values with a size num_points, the user can call:

my_array = (ctypes.c_ushort * num_points)()

Arrays created in this way are not dynamically sized, but they are much faster and do not require a copy when used with a C library like UL.

Users may want to import the Python numpy library as it provides a multidimensional array object and tools for working with arrays. Numpy is commonly used as an alternative to directly using c-type arrays.

View the example program ULAI02.py with a text editor for an example of using arrays in Python with the UL library.

### Multiple return values

Python doesn't typically use pointers for parameters, unlike C and other languages, and can return multiple values if needed. The following example shows a pulse output operation in C/C++ using pointers and in Python using multiple return values:

##### Pulse output example showing multiple return values/pointers

C/C++

int BoardNum = 0;
int Chan = 0;
double Frequency = 100, DutyCycle = 0.5, InitialDelay = 0;
ULStat = cbPulseOutStart(

BoardNum, Chan, &Frequency, &DutyCycle, 0, &InitialDelay, IDLE_LOW, 0);

displayActualValues(Frequency, DutyCycle, InitialDelay)

Python

try:

board_num = 0
timer_num = 0
freq = 100
duty_cycle = 0.5
initial_delay = 0

act_freq, act_duty_cycle, act_initial_delay = ul.pulse_out_start(

board_num, timer_num, freq, duty_cycle,
initial_delay, 0, TimerIdleState.IDLE_LOW, 0)

display_actual_values(act_freq, act_duty_cycle, act_initial_delay)

except ULError as e:

util.show_ul_error(e)

### Error Handling

Python does not return error codes but rather throws an exception when an error occurs. The exception contains the error code and error message.

We recommend that users program the try/except construct around each function to manage exceptions.

Note: Some of the Python API functions return a warning. For example, the pre-trigger functions will return a warning rather than throwing an exception when there isn't enough data. Likewise, the thermocouple input scan method will return a warning rather than an exception when the value is out of range or when an open thermocouple is detected.

The code below is a basic analog input example showing how error handling is performed in C/C++ and in Python.

##### Basic analog input example

C/C++

int BoardNum = 0;
int UDStat = 0;
int Chan;
int Gain = BIP5VOLTS;
WORD DataValue = 0;

UDStat = cbAIn(BoardNum, Chan, Gain, &Value, Options);

if(UDStat) {

printf("An error occurred, Error Code = %d", UDStat);

} else {

printf("%u", Value);

}

Python

board_num = 0
channel = 0
ai_range = ULRange.BIP5VOLTS

try:

# Get a value from the device
value = ul.a_in(board_num, channel, ai_range)
# Display the value
print("Value = " + str(value))

except ULError as e:

util.show_ul_error(e)

### Importing Python for Windows example programs into an IDE

Python for Windows example programs examples can be imported into any IDE that supports Python, such as Eclipse (Neon and later) or Visual Studio (2015 and later).

Before performing the following steps, install the Python UL Library using the instructions documented in the Getting Started topic.

1. Download the examples from the mcculw GitHub page at github.com/mccdaq.
2. Create a new folder and unzip the examples to the folder location. For this example, the programs are unzipped to C:\Users\Public\Documents\Measurement Computing\DAQ\Python.
3. Perform the procedures below to import the example programs into Eclipse or Visual Studio:

- For Eclipse instructions, click Importing Python for Windows example programs into Eclipse with PyDev.
- For Visual Studio instructions, click Importing Python for Windows example programs into Visual Studio with Python Tools for Visual Studio (PTVS).

#### Importing the Python for Windows example programs into Eclipse with PyDev

Eclipse Neon.3 – Eclipse IDE for Java Developers required. Other versions of Eclipse will be similar. These instructions assume you have already installed Eclipse.

1. Open an Eclipse workspace; close the Welcome page if it opens.
2. Install the PyDev plugin if it is not already installed:
   1. Go to Help»Install New Software; the Install dialog box opens.
   2. Click Add, and enter http://pydev.org/updates.
   3. Select all of the items listed, and follow the prompts to install.
3. Right click in the Package Explorer, and go to New»Project.
   The New Project dialog box opens.
4. Open the PyDev folder, select PyDev Project, and click Next.
5. Enter a name for the new project, such as mcculw examples in the Project name texbox.
6. Under the Project contents area, uncheck Use default and specify the directory where the Python UL is located, typically C:\Users\Public\Documents\Measurement Computing\DAQ\Python. This path must be exact, since a Python namespace is directly tied to the directory structure.
7. If you haven't done so already, configure the interpreter by clicking the link provided.

1. Select PyDev»Interpreter»Python Interpreter.
2. Click New.
3. Enter a name for this interpreter, such as Python.
4. Browse to the python executable (python.exe) installed on your system, and click OK.
   The necessary files are added to the path.
5. Apply the changes.

8. Click Finish to complete the process.

##### Running the examples

Follow the procedure below to run console-based examples or user interfaced-based Python for Windows example programs.

1. In the PyDev Package Explorer, expand either mcculw\examples\console or mcculw\examples\ui folder.
2. Right click on the example you wish to run, hover over Debug As and select Python Run.
3. After running the example once, subsequent runs may be performed by clicking on the Debug button on the toolbar, or by pressing the F11 key on the keyboard.

#### Importing the Python for Windows example programs into Visual Studio with Python Tools for Visual Studio (PTVS)

The following instructions are intended for Visual Studio 2017. Other versions of Visual Studio should be similar. These instructions assume you have already installed Visual Studio 2017 with the PTVS.

1. Open Visual Studio, and select File»New»Project.
   The New Project dialog box opens.
2. Select Python.
3. Select From Existing Python code.
4. Enter a name for the project, such as mcculw examples.
5. In the Location text box, browse to the directory where PyUL is installed, typically C:\Users\Public\Documents\Measurement Computing\DAQ\Python, and click OK. This path must be exact, since Python namespaces are directly tied to the directory structure.
   The Create New Project from Existing Python Code Wizard dialog box opens.
6. Click Finishto complete the wizard.
7. In the Solution Explorer, right click on Search Paths, select …, and add the Python UL directory (typically C:\Users\Public\Documents\Measurement Computing\DAQ\Python\mcculw), and click Select Folder.

##### Running the examples

User-interface-based examples and console-based examples are installed. Perform the rollowing procedure to run an examply program.

1. From the Solution Explorer, expand either the mcculw\examples\console or mcculw\examples\ui folder.
2. Right click on the example you wish to run and choose Set as Startup File.
3. Run the selected example by pressing the Start button on the standard toolbar, or the F5 key on the keyboard.

## Differences between the UL, UL for .NET, and Python

The table below lists the main differences between the Universal Library, Universal Library for .NET, and Python.

| Universal Library | Universal Library for .NET | Python
Platform | Standard Windows platform | The Microsoft .NET framework must be installed on development and distribution PCs. | Standard Windows platform; the library can be imported into any Python-supporting IDE such as Eclipse and Visual Studio.
Board Number | The board number is included as a parameter to the board functions. | An MccBoard class is created for each board installed, and the board number is passed to that board class. | The board number is included as a parameter to the board functions.
Functions | Set of function calls defined in a header. | Set of methods in the MccBoard and MccService classes. To access a method, instantiate a UL for .NET class and call the appropriate method using that class. | Set of function calls defined in a Python module.
Constants | Constants are defined and assigned a value in the header file. | Constants are defined as enumerated types. | Constants are defined as enumerated types.
Error handling | An error code is returned. | An ErrorInfo object that contains the error number and message is returned. | An exception is thrown which contains the error code and error message. Some functions return a warning if the error can be ignored.

### Example

The following example demonstrates how to call the AIn() method from within a 32-bit UL application, .NET application, and Python application:

VB program using the UL | VB program using UL for .NET | Python for Windows program
Dim Board As Integer | Dim Board0 as MccBoard Board0 = new MccDaq.MccBoard(0)

VB program using the UL | VB program using UL for .NET | Python for Windows program
Dim Board As Integer Dim Channel As Integer Dim Range As Integer Dim ULStat As Integer Dim DataValue As Short Board = 0 Channel = 0 Range = BIP5VOLTS; ULStat = cbAIn(Board, Channel, Range, DataValue) | Dim Board0 as MccBoard Board0 = new MccDaq.MccBoard(0) Dim Channel As Integer Dim Range As MccDaq.Range Dim ULStat As ErrorInfo Dim DataValue As UInt16 Channel = 0 Range = Range.BIP5VOLTS; ULStat = Board0.AIn(Channel, Range, DataValue) | board_num = 0 channel = 0 ai_range = ULRange.BIP5VOLTS try: # Get a value from the device value = ul.a_in(board_num, channel, ai_range) # Display the value print("Value = " + str(value)) except ULError as e: util.show_ul_error(e)