dmercer

Create custom PC applications for Analog Discovery

Blog Post created by dmercer Employee on Aug 9, 2013

Create custom PC applications for Analog Discovery

The WaveForms SDK just released with version 2.5.4 of the software includes a public application programming interface (API) that gives users the ability to create custom PC applications.


The WaveForms SDK User’s Manual, which you should familiarize yourself with before proceeding, that is supplied with the software installation assumes the user will be writing their custom applications in C++. In this Blog I will show you how to access these API functions from other popular programing languages and environments such as Python, Tcl and Octave.


The WaveForms Runtime is comprised of the DWF Dynamic Library and several configuration files. In the Windows version, this is a Dynamic Link Library named dwf.dll and is installed in the System directory ( “C:\Windows\System32” on most systems ).


In Python:


The Python scripting language supports a way to load and call functions from dynamic link libraries. The following few lines of code will load the dwf.dll functions:


# load Digilent Waveforms DLL functions

from ctypes import *

cdll.LoadLibrary("dwf")  # looks for .dll in C:\Windows\System32

libdwf = CDLL("dwf")


Most of the time you can simply pass ordinary Python variables to the functions but in some cases you must pass the variables by reference and you will need to define them as c type variables as in this example for the hardware handle:

# interface handle

hdwf = c_int()

Now to open the first Analog Discovery device found you call the open function and pass hdwf by reference:

# open automatically the first available device

libdwf.FDwfDeviceOpen(-1, byref(hdwf))

The hdwf variable now contains the hardware interface handle that you use in the rest of the function calls like this one that enables the positive 5 volt supply for example:

# enable positive supply

libdwf.FDwfAnalogIOChannelNodeSet(hdwf, 0, 0, 1)

At the end you would for example close the device as follows:

# close all opened devices by this process

libdwf.FDwfDeviceCloseAll()

 

In Tcl:

The Tcl scripting language does not come with a built in means of calling functions contained in a dll. You will need to install one of the add on packages that do that. I’ve tested the following and was able to get it working:

http://sourceforge.net/projects/tcl-dll-caller/

Download and add the extracted files from tcl_dll_bin_beta.zip to your Tcl installation.

The following few lines of code will load the dwf.dll functions:

# load Digilent Waveforms DLL functions

global type

package require dllcaller

dllcaller::load dwf     # looks for .dll in C:\Windows\System32

Next you will need to define all the functions from the library you will be using, for example:

dwf::cmd "int FDwfGetVersion(char*)"

dwf::cmd "int FDwfDeviceOpen(int, int*)"

dwf::cmd "int FDwfDeviceClose(int)"

dwf::cmd "int FDwfAnalogIOChannelNodeSet(int, int, int, int)"

dwf::cmd "int FDwfAnalogIOEnableSet(int, int)"

To return a string variable from a function call you need to first define the variable like:

# define a 32 character long string to get software version

set szVersion [::dll::buffer 32]

The following lines get the software version, opens the first device and turns on the + and – fixed 5 volt power supplies as an example:

::dwf::FDwfGetVersion $szVersion

puts "Software version $szVersion"

set hdwf 0

# Open device

::dwf::FDwfDeviceOpen -1 hdwf

puts "open returned $hdwf"

::dwf::FDwfAnalogIOChannelNodeSet $hdwf 0 0 1

::dwf::FDwfAnalogIOChannelNodeSet $hdwf 1 0 1

::dwf::FDwfAnalogIOEnableSet $hdwf 1

# Close Device

::dwf::FDwfDeviceClose $hdwf

 

In Octave:

GNU Octave is a high-level interpreted language, primarily intended for numerical computations. It also provides extensive graphics capabilities for data visualization and manipulation. Octave does not include a built in means of calling functions contained in a dll. However, for Octave versions 3.6 and later, it is possible to write short C++ code wrapper files around the C++ functions and compile the wrapper file into a oct function.

Linking external C code to Octave is relatively simple, as the C functions can easily be called directly from C++. Here is an example wrapper C++ code file ( file should be named FDwfGetVersion.cc ) that makes an Octave function, FDwfGetVersion.oct, that mirrors the dwf library FDwfGetVersion function:

#include <octave/oct.h>

/* ------------------------------------------------------------ */

/*              Include File Definitions                        */

/* ------------------------------------------------------------ */

 

#ifdef WIN32

    #include <windows.h>

#endif

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

 

#ifndef WIN32

    #include <unistd.h>

    #include <sys/time.h>

#endif

 

/* need path to header file, may change based on installation */

 

#include "C:/Program Files/Digilent/WaveFormsSDK/inc/dwf.h"

 

/* ------------------------------------------------------------ */

/*              Local Type Definitions                        */

/* ------------------------------------------------------------ */

 

DEFUN_DLD (FDwfGetVersion, args, nargout,

       "Get software version")

{

   octave_value_list retval;

   char szVersion(32);

   // retrieve input arguments from args

   int status;

   // call DWF routine

   status = FDwfGetVersion(&szVersion);

   // assign output arguments to retval

   retval(0) = status;

   retval(1) = szVersion;

   return retval;

}

 

The basic command to build oct-files is mkoctfile and it can be called from within octave or from the command line. There is one serious wrinkle in using mkoctfile with the normal Windows installation of Waveforms. Normally, the package is installed in C:\Program Files\Digilent. The path contains a space character and mkoctfile and the g++ linker can’t deal with paths with space characters in them. So the simple way around this is to copy this file:

C:\Program Files\Digilent\WaveFormsSDK\lib\x86\dwf.lib

to a directory in or near where you are working on the wrapper files. For example in a subdirectory like:

WaveFormsSDK\lib\x86\dwf.lib

Then you can direct mkoctfile to find this library file like this:

mkoctfile FDwfGetVersion.cc –L./WaveFormsSDK/lib/x86 -ldwf.lib

If all goes well you should end up with a file named FDwfGetVersion.oct which you can call from the Octave command line or as a function in an Octave program.

This procedure of writing wrapper files for each function you will be using might be a bit tedious at first but once you have them all written and compiled you are done and can use them over and over in multiple Octave programs.

What’s Next

There are probably other programing languages out there that could be interfaced with this API function library and used to program and control Analog Discovery. If you come up with interesting custom programs for Analog Discovery why not post them here on EngineerZone for others to use and adapt for their purposes.

As always I welcome comments and suggestions from the user community out there.

Doug

Outcomes