if (err == 2)
4.1.2 - Multi-Threaded Operation
The UD driver is completely thread safe. With some very minor exceptions, all these functions can be called from multiple threads
at the same time and the driver will keep everything straight. Because of this Add, Go, and Get must be called from the same
thread for a particular set of requests/results. Internally the list of requests and results are split by thread. This allows multiple
threads to be used to make requests without accidentally getting data from one thread into another. If requests are added, and
then results return
LJE_NO_DATA_AVAILABLE
or a similar error, chances are the requests and results are in different threads.
The driver tracks which thread a request is made in by the thread ID. If a thread is killed and then a new one is created, it is
possible for the new thread to have the same ID. Its not really a problem if Add is called first, but if Get is called on a new thread
results could be returned from the thread that already ended.
As mentioned, the list of requests and results is kept on a thread-by-thread basis. Since the driver cannot tell when a thread has
ended, the results are kept in memory for that thread regardless. This is not a problem in general as the driver will clean it all up
when unloaded. When it can be a problem is in situations where threads are created and destroyed continuously. This will result in
the slow consumption of memory as requests on old threads are left behind. Since each request only uses 44 bytes, and as
mentioned the ID’s will eventually get recycled, it will not be a huge memory loss. In general, even without this issue, it is strongly
recommended to not create and destroy a lot of threads. It is terribly slow and inefficient. Use thread pools and other techniques to
keep new thread creation to a minimum. That is what is done internally.
The one big exception to the thread safety of this driver is in the use of the Windows TerminateThread() function. As is warned in
the MSDN documentation, using TerminateThread() will kill the thread without releasing any resources, and more importantly,
releasing any synchronization objects. If TerminateThread() is used on a thread that is currently in the middle of a call to this driver,
more than likely a synchronization object will be left open on the particular device and access to the device will be impossible until
the application is restarted. On some devices, it can be worse. On devices that have interprocess synchronization, such as the
U12, calling TerminateThread() may kill all access to the device through this driver no matter which process is using it and even if
the application is restarted. Avoid using TerminateThread()! All device calls have a timeout, which defaults to 1 second, but can be
changed. Make sure to wait at least as long as the timeout for the driver to finish.
4.2 - Function Reference
The LabJack driver file is named LabJackUD.dll, and contains the functions described in this section.
Some parameters are common to many functions:
LJ_ERROR
– A LabJack specific numeric errorcode. 0 means no error. (long, signed 32-bit integer).
LJ_HANDLE
– This value is returned by OpenLabJack, and then passed on to other functions to identify the opened
LabJack. (long, signed 32-bit integer).
To maintain compatibility with as many languages as possible, every attempt has been made to keep the parameter types very
basic. Also, many functions have multiple prototypes. The declarations that follow, are written in C.
To help those unfamiliar with strings in C, these functions expect null terminated 8 bit ASCII strings. How this translates to a
particular development environment is beyond the scope of this documentation. A const char * is a pointer to a string that won’t be
changed by the driver. Usually this means it can simply be a constant such as “this is a string”. A char * is a pointer to a string that
will be changed. Enough bytes must be preallocated to hold the possible strings that will be returned. Functions with char * in their
declaration will have the required length of the buffer documented below.
Pointers must be initialized in general, although null (0) can be passed for unused or unneeded values. The pointers for
GetStreamData and RawIn/RawOut requests are not optional. Arrays and char * type strings must be initialized to the proper size
before passing to the DLL.
4.2.1 - ListAll()
Returns all the devices found of a given DeviceType and ConnectionType. Searching over Ethernet relies on the DiscoveryUDP
function (Section 5.2.3), which might not work on certain network configurations.
ListAllS() is a special version where DeviceType and ConnectionType are strings rather than longs. This is useful for passing string
constants in languages that cannot include the header file. The strings should contain the constant name as indicated in the header
file (such as “LJ_dtUE9” and ”LJ_ctUSB”). The declaration for the S version of open is the same as below except for (const char
*pDeviceType, const char *pConnectionType, …).
Declaration:
LJ_ERROR _stdcall ListAll ( long DeviceType,
long ConnectionType,
long *pNumFound,
long *pSerialNumbers,
long *pIDs,
double *pAddresses)
Parameter Description:
Returns: LabJack errorcodes or 0 for no error.
Inputs:
DeviceType
– The type of LabJack to search for. Constants are in the labjackud.h file.
ConnectionType
– Enter the constant for the type of connection to use in the search.
pSerialNumbers
– Must pass a pointer to a buffer with at least 128 elements.
pIDs
– Must pass a pointer to a buffer with at least 128 elements.
pAddresses
– Must pass a pointer to a buffer with at least 128 elements.
Outputs:
pNumFound
– Returns the number of devices found, and thus the number of valid elements in the return arrays.
pSerialNumbers
– Array contains serial numbers of any found devices.
pIDs
– Array contains local IDs of any found devices.
pAddresses
– Array contains IP addresses of any found devices. The function DoubleToStringAddress() is useful to convert
these to string notation.
4.2.2 - OpenLabJack()
Call OpenLabJack() before communicating with a device. This function can be called multiple times, however, once a LabJack is
open, it remains open until your application ends (or the DLL is unloaded). If OpenLabJack is called repeatedly with the same
parameters, thus requesting the same type of connection to the same LabJack, the driver will simply return the same LJ_HANDLE
every time. Internally, nothing else happens. This includes when the device is reset, or disconnected. Once the device is
reconnected, the driver will maintain the same handle. If an open call is made for USB, and then Ethernet, a different handle will be
returned for each connection type and both connections will be open.
OpenLabJackS() is a special version of open where DeviceType and ConnectionType are strings rather than longs. This is useful
for passing string constants in languages that cannot include the header file. The strings should contain the constant name as
indicated in the header file (such as “LJ_dtUE9” and ”LJ_ctUSB”). The declaration for the S version of open is the same as below
except for (const char *pDeviceType, const char *pConnectionType, …).
26