« Close

Datasheets and User Guides

App Notes

Software & Driver

 

4.3.7 - Stream Mode

Subsections

Stream Mode Overview

There are five IOTypes used to control streaming:

LJ_ioCLEAR_STREAM_CHANNELS
LJ_ioADD_STREAM_CHANNEL
LJ_ioSTART_STREAM        //Value returns actual scan rate.
LJ_ioSTOP_STREAM
LJ_ioGET_STREAM_DATA

The following constant is passed in the Channel parameter with the get stream data IOType to specify a read returning all scanned channels, rather than retrieving each scanned channel separately:

LJ_chALL_CHANNELS

The following are special channels, used with the get/put config IOTypes, to write or read various stream values:

LJ_chSTREAM_SCAN_FREQUENCY
LJ_chSTREAM_BUFFER_SIZE         //UD driver stream buffer size in samples.
LJ_chSTREAM_CLOCK_OUTPUT        //True/False. [1]
LJ_chSTREAM_EXTERNAL_TRIGGER    //True/False. [1]
LJ_chSTREAM_WAIT_MODE
LJ_chSTREAM_BACKLOG_COMM        //Read-only.  0=0% and 128=100%.
LJ_chSTREAM_BACKLOG_CONTROL     //Read-only.  Number of samples.
LJ_chSTREAM_BACKLOG_UD          //Read-only.  Number of samples.
LJ_chSTREAM_SAMPLES_PER_PACKET  //Read-only.  Always 16 on the UE9.
LJ_chSTREAM_READS_PER_SECOND    //Default 25.
[1] See Section 3.2.1.

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         //Advance 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 hardware stream buffers on the UE9. 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 Control processor acquires data at precise intervals, and transfers it to the Comm processor which has a large data buffer. The Control processor has a small data buffer (256 samples) for data waiting to be transferred to the Comm processor, and the LJ_chSTREAM_BACKLOG_CONTROL special channel specifies the number of samples remaining in the Control buffer. If this parameter is nonzero and growing, it suggests that the Control processor is too busy. Because the Control buffer is so small, overflows very quickly, and generally only overflows if sampling faster than the specified rates, this parameter is not often used.

The Comm processor holds stream data in a 4 Mbit FIFO buffer (512 Kbytes, 11397 StreamData packets, 182361 samples) until it can be sent to the host. The lower 7 bits of the LJ_chSTREAM_BACKLOG_COMM special channel specify how much data is left in the Comm buffer in increments of 4096 bytes. A value of 0 means the buffer is empty and a value of 128 (or higher) means the buffer has overflowed. The UD driver retrieves stream data from the UE9 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 UE9 is acquiring it, and thus there will be data left over in the UE9 buffer.

To obtain the maximum stream rates documented in Section 3.2, the data must be transferred between host and UE9 in large chunks. The amount of data transferred per low-level packet is fixed at 16 samples on the UE9. 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.

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. In addition to the stream parameters configured below, some applications might also need to configure analog input settings such as range and resolution:

//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 AIN2 then AIN3.
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, 3, 0, 0, 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.
while(!done)
{
    //Must set the number of scans to read each iteration, as the read
    //returns the actual number read.
    numScans = 1000;

    //Read the data.  Note that the array passed must be sized to hold
    //enough SAMPLES, and the Value passed specifies the number of SCANS
    //to read.
    eGetPtr(lngHandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, &numScans, array);
    actualNumberRead = numScans;

    //When all channels are retrieved in a single read, the data
    //is interleaved in a 1-dimensional array.  The following lines
    //get the first sample from each channel.
    channelA = array[0];
    channelB = array[1];

    //Retrieve the current Comm backlog.  The UD driver retrieves
    //stream data from the UE9 in the background, but if the computer
    //is too slow for some reason the driver might not be able to read
    //the data as fast as the UE9 is acquiring it, and thus there will
    //be data left over in the UE9 buffer.
    eGet(lngHandle, LJ_ioGET_CONFIG, LJ_chSTREAM_BACKLOG_COMM, &dblCommBacklog, 0);

    //Retrieve the current UD driver backlog.  If this is growing, then
    //the application software is not pulling data from the UD driver
    //fast enough.
    eGet(lngHandle, LJ_ioGET_CONFIG, LJ_chSTREAM_BACKLOG_UD, &dblUDBacklog, 0);
}

Finally, stop the stream:

//Stop the stream.
errorcode = ePut (Handle, LJ_ioSTOP_STREAM, 0, 0, 0);

9 comments

Could you tell me what is the value of the LJ_chSTREAM_BACKLOG_UD constant for the UE9?

It is not defined in our ljud_constants file.

Thank you for your help.

It is 4107, which you can find in LabJackUD.h.  You can also use StringToConstant() to convert the names to numbers.

Thank you for the quick reply. That's exactly what I wanted to know.

Dear Sir/Madam,

Could you tell me what exactly LJ_ioCLEAR_STREAM_CHANNELS does?

Thank you for your help.

 

Kind regards,
Dennis

 

It clears the scan list.  Say you made a 2-channel scan list with AIN2-AIN3 as shown above using a couple requests with add-stream-channel.  Then you start the stream and then stop the stream.  Then you decide you want a 2-channel scan list with AIN2-AIN4, so you do 2 requests to add those channels to the scan list, but forget to first clear the scan list, what you would then have is a 4-channel scan list with AIN2-AIN3-AIN2-AIN4.

Thank you for your help. That is exactly what I wanted to know.

Josefina Meirovich's picture

Hello! I'm working with the LabJack U3-HV and Matlab for my final proyect. I am doing a streaming similar to that of the examples, but with more channels. I'm working with the GUI of Matlab and I want to start the streaming by pressing a toggle button and stream for a certain time, and also I want to stop it whenever the user wants by pressing the toggle button a second time. I can start the streaming using the same code that you provide in the examples but when I want to stop it I write this code:

[ljerror, dblCommBacklog] = ljudObj.eGet(handles.ljhandle,LabJack.LabJackUD.IO.GET_CONFIG,LabJack.LabJackUD.CHANNEL.STREAM_BACKLOG_COMM, dblCommBacklog, dummyDoubleArray);

[ljerror, dblUDBacklog] = ljudObj.eGet(handles.ljhandle, LabJack.LabJackUD.IO.GET_CONFIG, LabJack.LabJackUD.CHANNEL.STREAM_BACKLOG_UD, dblUDBacklog, dummyDoubleArray);

%Stop the stream   

ljudObj.eGet(handles.ljhandle, LabJack.LabJackUD.IO.STOP_STREAM, 0, 0, 0);    

msgbox('Stop button pressed')

I get the message box I want, but I also obtain an error message saying "UD Error: Stream not running".

Do you know what is wrong in the code?

Thank you in advance!

LabJack Support's picture

The "Stream not running" error (LJE_STREAM_NOT_RUNNING, error code 9) occurs when trying to read stream data (LabJack.LabJackUD.IO.GET_STREAM_DATA) but stream mode is not running.

Probably your toggle button stops stream mode, but your code is still reading stream data afterwards causing the error.

Josefina Meirovich's picture

Thank you for your help!