There may be applications, most likely ones running in the Runtime version of DAQFactory, where you do not know the ID or address of the LabJack when creating the application and so can't hard code this in. Because of this, the LabJack driver has a function to allow you to manually open a LabJack, returning a device number that you can use with the rest of the functions just like before. For example, to open a UE9 at Ethernet address 192.168.2.1, you might do:
global DNum
private err
err = OpenLabJack(LJ_dtUE9, LJ_ctETHERNET, "192.168.2.1", 0, @DNum)
if (err != LJE_NOERROR)
// failed to open
endif
This of course assumes you've done your using() and include() calls elsewhere already. In this example we used static parameters, but there is no reason you couldn't replace any or all of the parameters with variables that could be edited by the end user from pages you created.
Once successfully called, you should then use the DNum variable in all your other LabJack function calls.
A few points:
The Raw In and Raw Out functions (LJ_ioRAW_IN, LJ_ioRAW_OUT), and several other functions of the LabJack require an array pointer. You can pass a pointer to an array, just like you've been passing references to variables, using the @ sign. Just make sure you have preinitialized the array to the correct amount. So, using the example in the LabJack User's Guide for Raw In and Out, the DAQFactory script would look like this (assuming first found and that you've done the using() and include() somewhere else):
private writeArray = {0x70,0x70}
private readArray = {0x00,0x00}
private NumBytesToWrite = 2
private NumBytesToRead = 2
eGet(0, LJ_ioRAW_OUT, 0, @NumBytesToWrite, @writeArray)
eGet(0, LJ_ioRAW_IN, 0, @NumBytesToRead, @readArray)
Internally, DAQFactory will convert the array of double precision values, which is the only numeric data type supported in DAQFactory, to an array of bytes. This means that each element in the array should be between 0 and 255. The array also must be 1 dimensional. Most importantly, the array MUST be preinitialized to the proper length. The driver does not look at the previous parameter to make sure you have the correct array size, any more than the C version would do. If you do not preinitialize, you are likely to crash DAQFactory. Worse, it may work sometimes, but crash others, so be careful with this one.
LabJack devices support serial communications using their digital lines using the standard SPI synchronous format. This is a powerful but advanced feature of the LabJack, though the details of SPI are beyond the scope of this guide.
Following is sample code that demonstrates SPI usage. It uses:
The code sends out a string of 16 bytes and prints the received string to the command / alert window. If you short MISO to MOSI, then the 16 bytes sent out are echoed back. If MISO is tied to GND, then all zeros are received and printed. If you tie MISO to VS or leave it unconnected, then all 255's are received and printed.
using("device.labjack")
include("c:\program files\labjack\drivers\labjackud.h")
global ID = 0 // use first found
//First, we do a pin config reset to set the LabJack to factory defaults.
ePut(ID,LJ_ioPIN_CONFIGURATION_RESET,0,0,0)
// Configure the SPI communication:
//Enable automatic chip-select control.
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_AUTO_CS,1,0,0)
//Mode A: CPHA=0, CPOL=0.
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_MODE,0,0,0)
//125kHz clock.
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_CLOCK_FACTOR,0,0,0)
//MOSI is FIO2
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_MOSI_PIN_NUM,2,0,0)
//MISO is FIO3
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_MISO_PIN_NUM,3,0,0)
//CLK is FIO0
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_CLK_PIN_NUM,0,0,0)
//CS is FIO1
AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chSPI_CS_PIN_NUM,1,0,0)
//Execute the requests on a single LabJack. The driver will use a single low-level TimerCounter command to hand
GoOne(ID)
// now that its setup, do the communication. Note that you can do this part in a separate sequence, and run mul
// without the reconfiguring the SPI with the above code.
// initialize the variables
private numSPIBytesToTransfer=4
private dataArray
dataArray[0] = 170
dataArray[1] = 138
dataArray[2] = 85
dataArray[3] = 21
//Transfer the data. The write and read is done at the same time.
eGet(ID, LJ_ioSPI_COMMUNICATION, 0, @numSPIBytesToTransfer, @dataArray)
// print the read to the command / alert window. Of course you'll probably do something a bit more exciting wit
? dataArray
Each time you run the script, the 4 bytes of dataArray will be written and then 4 bytes will be read back and printed to the command / alert window. As mentioned in the script comments, you can do the actual communication multiple times without re-running reconfiguration script at the top of this sample.
Note that the UD example code provides similar code to the above script in C.
In many places in this guide, we've split apart things that occur at less than 100hz, and those that are faster. This is because Windows needs to have some CPU time to redraw the screen, move the mouse and perform other tasks and thus can't really do things at an interval faster than 100hz.
However, if you have a multicore or multiprocessor computer, you can take advantage of DAQFactory's design and the multiple cores to achieve faster software polled rates than would be possible with a single core. The trick to this is making sure that all your fast processes, i.e. anything faster than 50hz or so, is done in a single thread.
What's a thread? You've seen Windows do multiprocessing before when you are downloading a big file off the internet and you switch to another program to check your email at the same time. A thread is just like different programs that can run simultaneously, but that exist inside of a single program like DAQFactory. DAQFactory is made up of a lot of different threads and so can perform multiple tasks simultaneously. Likewise, it can split these threads across multiple cores or processors for maximum efficiency.
There are basically two ways you can keep things on a single thread in DAQFactory. The first is to put all the tasks in a single sequence. Each sequence is run in its own thread, unless of course it is called as a function from another sequence. This is why you can create multiple sequences to perform different tasks and run them all simultaneously. The other way is to create Channels, and give all the desired high speed channels the same Timing and Offset values. If Channels have different Timing or Offset, then they are put on a different thread.
If you have multiple processors or cores and want to see this in action, just create a few analog input channels and set their Timing to 0.001. This will chew up much of the processor power of one of your cores, but will leave Windows the other core to perform its tasks. In fact, as I am typing this, I have DAQFactory running reading an analog input from a LabJack at full speed, and I see no lag in my typing.
That all said, its important to understand that there is a limit to how fast the LabJack itself can process commands. If you perform the test with a few Channels with Timing = 0.001, and then go to the Table tab of one of the channels, you will see that the data actually comes in about every 4 milliseconds. This is because although DAQFactory is trying to read it at 1 millisecond intervals, the LabJack is taking about 4 milliseconds to actually perform the command.
The LJ_ioSET_STREAM_CALLBACK, LJ_ioSET_EVENT_CALLBACK and any other LabJack function that requires a function pointer are not supported. These particular two callback's are handled internally by DAQFactory. The first allows DAQFactory to process streaming data, while the second handles connect and disconnect messages from the driver.
Also, you should not change the LJ_chSTREAM_WAIT_MODE, as all waiting is handled internally. If you change this, you will most likely cause streaming to stop functioning.