The mechanism used within LabVIEW to call a routine from either of these libraries is different from that used in the case of the .NET Library. This is because that library is a so-called .NET assembly, whilst the C and Fortran libraries are (on the Windows platform) dynamic link libraries (DLLs). The .NET assembly uses the common language runtime (CLR) and the .NET framework to manage assembly functions, and to export information about classes, methods, properties and events. The practical implication of this is that when a method from the NAG Library for .NET is loaded into LabVIEW, information about its function arguments is automatically loaded as well. This is not the case with a DLL, as we shall see.

As previously, we begin building a LabVIEW application by creating a blank virtual instrument (VI) using, for example, the

*Blank VI*option on LabVIEW’s Getting Started splash screen, and go to the

*block diagram*, which is where our routine will be loaded. Once again, we build our example around the NAG routine

**g01aa**, which performs simple statistical calculations on a set of ungrouped data; besides being implemented as a method in the .NET Library, it is also available in both the Fortran and the C libraries.

To load the routine, we first bring up the

**, using the option on the**

*Functions Palette**View*menu on the block diagram window. Next, we open the

**collection from the palette, and then the**

*Connectivity***item. This palette contains a variety of functions for calling code from libraries and executing system commands, and we select the**

*Libraries & Executables***item – which calls a DLL directly – and drag it onto the block diagram in order to initialize it. To specify the library we want to call, we right-click on the node and select**

*Call Library Function***. This brings up the**

*Configure...***dialog box, and we enter the name of the DLL in the**

*Call Library Function***box. In general, either the name or the path is acceptable, although the choice between between them has consequences if the VI is to be distributed or relocated. In our example, we're running LabVIEW under Windows, and are using the implementation of the NAG Fortran Library contained in**

*Library name or path***FLDLL224M_nag.dll**and the NAG C Library implementation in

**CLW3209DA_nag.dll**.

Having specified the library, we next select the name of the routine we wish to call by picking it from the drop-down list in the

**dialog box; in our example, this is**

*Function name***G01AAF**if we're using the NAG Fortran Library, or

**g01aac**if it's the NAG C Library that we're calling. In either case, we specify the calling convention as

**.**

*stdcall (WINAPI)*The next step is to tell LabVIEW about the argument list for our routine via the

**tab on the**

*Parameters***dialog box. For each parameter, we specify its name, type and how it is to be passed (as a value or a pointer to a value) to LabVIEW when it calls the routine. As these details are entered, LabVIEW updates the**

*Call Library Function***display at the bottom of the dialog box with the C prototype of the routine (LabVIEW is written in C, and it is from this language that the external routine is called). This table shows the parameters for**

*Function prototype***G01AAF**, including their Fortran type, their LabVIEW specification and the C type that LabVIEW generates for the function prototype:

Fortran variable name | NAG Fortran type | LabVIEW Type | LabVIEW Constant? | LabVIEW Data type | LabVIEW Pass | LabVIEW Array Format | LabVIEW C type |
---|---|---|---|---|---|---|---|

N | INTEGER | Numeric | Y | Signed 32-bit Integer | Pointer to Value | - | const int32_t* |

X | double precision array | Array | Y | 8-byte Double | - | Array Data Pointer | const double* |

IWT | INTEGER | Numeric | N | Signed 32-bit Integer | Pointer to Value | - | int32_t* |

WT | double precision array | Array | N | 8-byte Double | - | Array Data Pointer | double* |

XMEAN | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

S2 | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

S3 | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

S4 | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

XMIN | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

XMAX | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

WTSUM | double precision | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

IFAIL | INTEGER | Numeric | N | Signed 32-bit Integer | Pointer to Value | - | int32_t* |

Although there are several parameters, many of them have the same characteristics. Firstly we recall that, since Fortran passes arguments by reference (not by value), each parameter must be passed as a pointer when calling the Fortran routine from LabVIEW (i.e. from C). Next, the documentation for this implementation of the NAG Fortran Library tells us that

*double precision*means

**DOUBLE PRECISION**- that is, an 8-byte floating point number, whilst the Fortran

**INTEGER**type is a 32-bit integer. Hence, these two types can be respectively mapped to

**double**and

**int32_t**, via LabVIEW's

**and**

*8-byte Double***types. Finally, it can be seen how designating a variable as a constant (because it's only used on input to the routine) results in LabVIEW applying the**

*Signed 32-bit Integer***const**qualifier to the C type.

Similar remarks apply, for the most part, to the use of the

**g01aac**routine (note that the parameter list is slightly different for this version of the routine):

C variable name | NAG C type | LabVIEW Type | LabVIEW Constant? | LabVIEW Data type | LabVIEW Pass | LabVIEW Array Format | LabVIEW C type |
---|---|---|---|---|---|---|---|

n | Integer | Numeric | Y | Signed 32-bit Integer | Value | - | const int32_t |

x | const double array | Array | Y | 8-byte Double | - | Array Data Pointer | const double* |

wt | const double array | Array | Y | 8-byte Double | - | Array Data Pointer | const double* |

nvalid | Integer* | Numeric | N | Signed 32-bit Integer | Pointer to Value | - | int32_t* |

xmean | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

xsd | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

xskew | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

xkurt | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

xmin | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

xmax | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

wsum | double* | Numeric | N | 8-byte Double | Pointer to Value | - | double* |

fail | NagError* | Numeric | N | Signed 32-bit Integer | Value | - | int32_t |

Since we're now calling a C routine from C, there is a closer correspondence between the NAG type and the LabVIEW C type, although a couple of additional explanatory remarks might be necessary. Firstly, the NAG C Library uses a data type called

**Integer**; for this implementation, this is defined as

**long**, which is a 32-bit integer on Windows systems. Secondly, the

**fail**variable is a pointer to a C structure named

**NagError**; we access this using a 32-bit integer (not a pointer to an integer), which is the same size as the address of the structure.

More information about how to create an interface between LabVIEW and external libraries (including advice for more complicated cases than those used here) is available here. Having created the interface to the NAG routine, the final step is to add LabVIEW controls and indicators to handle the input and output of our application. This is exactly the same procedure as was described previously, and we conclude this post with Figure 1, which shows the block diagram of our application, centered around the

**, which is where the NAG routine (in this case,**

*Call Library Function***g01aac**) is being called.

This is an excellent introduction to calling NAG Fortran and C routines from LabVIEW.

ReplyDeleteFor me the key difference between the two libraries is how they handle fail conditions. The fortran routines pass a single integer value which determines how an error will be handled (hard or soft fail), and receives the error code on completion of the routine. Control of error handling with the C library functions requires the passing of C structures which is not at all straightforward from LabVIEW.

In principle, calling C routines from LabVIEW appears to be straightforward as LabVIEW follows many of the C conventions. However, as long as the differences between Fortran and C, such as the handling of strings and array are kept in mind both are reasonable easy to handle from LabVIEW. I've written more details on this here.

The above link also contains some hints on making the LabVIEW interface to the NAG libraries more readable, such as displaying terminal names in the call library function node and grouping similar input or output nodes together in clusters.

Many thanks for the helpful comment, Conway, and for the pointer to your article which contains a wealth of further useful information on this topic. Your main point here about the difference between calling the Fortran and C libraries from LabVIEW is, I think, well-taken: as noted, I used an integer for the address of the C structure. This satisfies the requirements of the calling protocol, but it's not possible (or at least, much more difficult) to make any use of the contents of the structure - i.e. we can't check for any error conditions.

ReplyDeleteFollowing this description of how to call NAG routines from LabVIEW, I've written some examples illustrating some aspects of this work. They're now available for download from our LabVIEW page which contains a link to an archive containing eighteen LabVIEW examples that use a variety of NAG routines and methods.

ReplyDeleteYou might like to know that I gave a presentation about enhancing LabVIEW using NAG Library routines earlier this week; the slides are available for download from our LabVIEW page and provide a self-contained account of how to do this (including a couple of specific example applications which use NAG routines), together with a description of how to construct a wrapper library around selected NAG functions, and then import that into LabVIEW.

ReplyDelete