| Customize Help

MIL functions and constants in Python



In C/C++, you would write out a MIL function call as listed in the MIL Reference; in Python, functions must be prefixed with the name of the library from which the function originates. Therefore, to reference a function within the MIL library in Python, add the prefix MIL. to the required MIL function. The following is an example call to MappAlloc():

MIL.MappAlloc(MIL.MIL_TEXT("M_DEFAULT"), MIL.M_DEFAULT, None)

Much like MIL function calls, MIL constants must also be prefixed by MIL. as is demonstrated above with MIL.M_DEFAULT. For constants that are used frequently, you might find it useful to associate the constant with a variable. For instance, you could declare a variable called M_DEFAULT as being equivalent to MIL.M_DEFAULT.

Data types

In most cases, you can pass a numerical value directly to a MIL function without explicitly casting it to the correct data type. However, when passing a variable to a MIL function in Python, the variable must be initialized with a value of an appropriate type. This is also true of variables being passed by reference.

Besides casting values to the standard types (for example, using Int()), you can cast values using the functions in the ctypes library. In addition, the MIL Python wrapper includes functions to cast values to certain, but not all, MIL data types. The MIL data types which are explicitly supported in Python are:

  • MIL_ID.

  • MIL_INT.

  • MIL_TEXT.

An example of declaring and initializing a variable as a MIL_ID is given below.

MILBufferId = MIL.MIL_ID(0)

Where 0 is cast to a MIL_ID and the variable MILBufferId is initialized to this value, causing it to be typed as a MIL_ID as well.

In a case where you need to pass one data type to a function (for example, a MIL_ID) but the function's parameter takes another data type (for example, a MIL_DOUBLE), you would initialize the variable with a value of the needed type (for example, MIL_ID) and then cast the content of the variable to the type expected by the parameter (for example, a double using ctype.c_double) as shown below. It is to be noted that this does not cast the variable MILBufferId to a double, but it casts the value of that variable to a double.

MIL.MdigControl(MilDigitizer, MIL.M_LUT_ID, ctypes.c_double(MIL.MILBufferId.value))

Pointers

Many MIL functions have a parameter that takes a reference to a variable as an input or as an output. In these situations, you should use the pointer functionality provided by the ctypes library. To use a pointer in Python, use the following syntax:

ctypes.byref(MILObject)

Alternatively, you can use:

ctypes.POINTER(MILObject)

Where the byref function will instantiate a reference to MILObject. The Pointer function will construct a real pointer object, allowing you to instantiate a Python reference to your original object (MILObject). If you only need to reference a variable of an intrinsic type, you should use the byref function; whereas, if you need to reference a structure, you must use Pointer.

Using strings in Python

Some MIL functions have a parameter that requires a reference to a variable in which a string will be written (for example, MdigInquire() with M_FORMAT). To pass a variable to a MIL function, it must be initialized with a value of the appropriate type. In this case, the variable would have to be initialized to a string. However, strings in Python are immutable (read-only). So, once the variable is initialized, it can't be changed. To overcome this problem, initialize the variable using the create_c_string_buffer function which creates a mutable memory block. This function is part of the MIL wrapper and as such must be prefixed with MIL..

When you call the create_c_string_buffer function, you must either pass a string or an integer representing the size of the required memory block. When you pass a string to the create_c_string_buffer function, the memory block will be one character larger to include the null-terminating character. If you pass an integer to the create_c_string_buffer function, the integer must account for the string and its null-terminated character.

Many MIL functions that return a string also provide a way of retrieving the size of that string. You can use this information to create a memory block of an appropriate size. This is done as follows:

stringSize = MIL.MdigInquire(MilDigitizer, MIL.M_FORMAT_SIZE, MIL.M_NULL)
UserString = MIL.create_c_string_buffer(stringSize+1)
MIL.MdigInquire(MilDigitizer, MIL.M_FORMAT, ctypes.byref(UserString))

When a MIL function has a string parameter and the function is not returning a string to the parameter or modifying a string passed to the parameter, you can pass MIL.MIL_TEXT("UserString") directly to the MIL function parameter, or set a variable to this string and pass the variable to the parameter.

Freeing objects in MIL

In Python, you typically don't need to preallocate or deallocate memory manually; the deallocation of objects in Python is handled by the garbage collector functions. However, since MIL is natively a C library, all objects have to be allocated and deallocated manually using one of the M...Alloc() functions or one of the M...Free() functions, respectively. The deallocation must be done for all allocated application contexts, systems, buffers, displays, and any other object that was allocated. Furthermore, the order in which you deallocate these objects should be the reverse order in which the objects were initially allocated.