With the wait mode special channel above, the following constants are passed in the value parameter to select the behavior when
reading data:
LJ_swNONE //No wait. Immediately return available data.
LJ_swALL_OR_NONE //No wait. Immediately return requested amount, or none.
LJ_swPUMP //Advanced message pump wait mode.
LJ_swSLEEP //Wait until requested amount available.
The backlog special channels return information about how much data is left in the stream buffer on the U3 or in the UD driver.
These parameters are updated whenever a stream packet is read by the driver, and thus might not exactly reflect the current state
of the buffers, but can be useful to detect problems.
When streaming, the processor acquires data at precise intervals, and transfers it to a buffer on the U3 itself. The U3 has a small
buffer (512-984 samples) for data waiting to be transferred to the host. The
LJ_chSTREAM_BACKLOG_COMM
special channel
specifies how much data is left in the U3 buffer (
COMM
or
CONTROL
are the same thing on the U3), where 0 means 0% full and
256 would mean 100% full. The UD driver retrieves stream data from the U3 in the background, but if the computer or
communication link is too slow for some reason, the driver might not be able to read the data as fast as the U3 is acquiring it, and
thus there will be data left over in the U3 buffer.
To obtain the maximum stream rates documented in Section 3.2, the data must be transferred between host and U3 in large
chunks. The amount of data transferred per low-level packet is controlled by
LJ_chSTREAM_SAMPLES_PER_PACKET
. The
driver will use the parameter
LJ_chSTREAM_READS_PER_SECOND
to determine how many low-level packets to retrieve per
read.
The size of the UD stream buffer on the host is controlled by
LJ_chSTREAM_BUFFER_SIZE
. The application software on the
host must read data out of the UD stream buffer fast enough to prevent overflow. After each read, use
LJ_chSTREAM_BACKLOG_UD
to determine how many samples are left in the buffer.
Since the data buffer on the U3 is very small a feature called auto-recovery is used. If the buffer overflows, the U3 will continue
streaming but discard data until the buffer is emptied, and then data will be stored in the buffer again. The U3 keeps track of how
many packets are discarded and reports that value. Based on the number of packets discarded, the UD driver adds the proper
number of dummy samples (-9999.0) such that the correct timing is maintained. Auto-recovery will generally occur when the U3
buffer is 90-95% full.
In stream mode the LabJack acquires inputs at a fixed interval, controlled by the hardware clock on the device itself, and stores the
data in a buffer. The LabJackUD driver automatically reads data from the hardware buffer and stores it in a PC RAM buffer until
requested. The general procedure for streaming is:
Update configuration parameters.
Build the scan list.
Start the stream.
Periodically retrieve stream data in a loop.
Stop the stream.
Following is example pseudocode to configure a 2-channel stream.
//Set the scan rate.
AddRequest (lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_SCAN_FREQUENCY, scanRate, 0, 0);
//Give the UD driver a 5 second buffer (scanRate * 2 channels * 5 seconds).
AddRequest (lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_BUFFER_SIZE, scanRate*2*5, 0, 0);
//Configure reads to wait and retrieve the desired amount of data.
AddRequest (lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_WAIT_MODE, LJ_swSLEEP, 0, 0);
//Define the scan list as singled ended AIN2 then differential AIN3-AIN9.
AddRequest (lngHandle, LJ_ioCLEAR_STREAM_CHANNELS, 0, 0, 0, 0);
AddRequest (lngHandle, LJ_ioADD_STREAM_CHANNEL, 2, 0, 0, 0);
AddRequest (lngHandle, LJ_ioADD_STREAM_CHANNEL_DIFF, 3, 0, 9, 0);
//Execute the requests.
GoOne (lngHandle);
Next, start the stream:
//Start the stream.
eGet(lngHandle, LJ_ioSTART_STREAM, 0, &dblValue, 0);
//The actual scan rate is dependent on how the desired scan rate divides into
//the LabJack clock. The actual scan rate is returned in the value parameter
//from the start stream command.
actualScanRate = dblValue;
actualSampleRate = 2*dblValue;
Once a stream is started, the data must be retrieved periodically to prevent the buffer from overflowing. To retrieve data, add a
request with IOType
LJ_ioGET_STREAM_DATA
. The Channel parameter should be
LJ_chALL_CHANNELS
or a specific
channel number (ignored for a single channel stream). The Value parameter should be the number of scans (all channels) or
samples (single channel) to retrieve. The x1 parameter should be a pointer to an array that has been initialized to a sufficient size.
Keep in mind that the required number of elements if retrieving all channels is number of scans * number of channels.
Data is stored interleaved across all streaming channels. In other words, if two channels are streaming, 0 and 1, and
LJ_chALL_CHANNELS
is the channel number for the read request, the data will be returned as Channel0, Channel1, Channel0,
Channel1, etc. Once the data is read it is removed from the internal buffer, and the next read will give new data.
If multiple channels are being streamed, data can be retrieved one channel at a time by passing a specific channel number in the
request. In this case the data is not removed from the internal buffer until the last channel in the scan is requested. Reading the
data from the last channel (not necessarily all channels) is the trigger that causes the block of data to be removed from the buffer.
This means that if three channels are streaming, 0, 1 and 2 (in that order in the scan list), and data is requested from channel 0,
then channel 1, then channel 0 again, the request for channel 0 the second time will return the same data as the first request. New
data will not be retrieved until after channel 2 is read, since channel 2 is last in the scan list. If the first get stream data request is for
10 samples from channel 1, the reads from channels 0 and 2 also must be for 10 samples. Note that when reading stream data
one channel at a time (not using
LJ_chALL_CHANNELS
), the scan list cannot have duplicate channel numbers.
There are three basic wait modes for retrieving the data:
LJ_swNONE: The Go call will retrieve whatever data is available at the time of the call up to the requested amount of data. A
Get command should be called to determine how many scans were retrieved. This is generally used with a software timed
read interval. The number of samples read per loop iteration will vary, but the time per loop iteration will be pretty consistent.
Since the LabJack clock could be faster than the PC clock, it is recommended to request more scans than are expected
each time so that the application does not get behind.
LJ_swSLEEP: This makes the Go command a blocking call. The Go command will loop until the requested amount of is
retrieved or no new data arrives from the device before timeout. In this mode, the hardware dictates the timing of the
application … you generally do not want to add a software delay in the read loop. The time per loop iteration will vary, but the
number of samples read per loop will be the same every time. A Get command should be called to determine whether all the
data was retrieved, or a timeout condition occurred and none of the data was retrieved.
LJ_swALL_OR_NONE: If available, the Go call will retrieve the amount of data requested, otherwise it will retrieve no data. A
Get command should be called to determine whether all the data was returned or none. This could be a good mode if
hardware timed execution is desirable, but without the application continuously waiting in SLEEP mode.
The following pseudocode reads data continuously in SLEEP mode as configured above:
//Read data until done.
37