« Close

Datasheets and User Guides

App Notes

Software & Driver

 

2.4.1 - eStreamStart

Initializes a stream object and begins streaming. This function creates a buffer in memory that holds data from the device, so that higher data throughput can be achieved.

    Syntax

    LJM_ERROR_RETURN LJM_eStreamStart(
                          int Handle, 
                          int ScansPerRead,
                          int NumAddresses, 
                          const int * aScanList, 
                          double * ScanRate) 
    

    Parameters

    Handle [in]
    A device handle. The handle is a connection ID for an active device. Generate a handle with LJM_Open or LJM_OpenS.
    ScansPerRead [in]
    The number of scans returned by each call to the LJM_eStreamRead function. Increase this parameter to get more data per call of LJM_eStreamRead. A typical value would be equal to ScanRate or 1/2 ScanRate, which results in a read once or twice per second.
    NumAddresses [in]
    The number of addresses in aScanList. The size of the aScanList array.
    aScanList [in]
    An array of addresses to stream. The scan list is the list of data addresses that are to be buffered by LJM and returned with LJM_eStreamRead. Find addresses in the Modbus Map. For example, to stream AIN3 add the address 6 to the scan list.
    ScanRate [in/out]
    A pointer that sets the desired number of scans per second. Upon successful return of this function, ScanRate will be updated to the actual scan rate that the device will use. Keep in mind that data rate limits are specified in Samples/Second which is equal to NumAddresses * Scans/Second.

    Returns

    LJM errorcodes or 0 for no error.

    Remarks

    To read data from stream, use LJM_eStreamRead. To stop stream, use LJM_eStreamStop.

    Configuration - Channel configuration such as range and resolution must be handled elsewhere. Check the device datasheet for details about analog inputs and which connection types are capable of stream.

    This function writes to the following registers, which cannot be set manually when using LJM_eStreamStart:

    • STREAM_SCANRATE_HZ
    • STREAM_NUM_ADDRESSES
    • STREAM_SAMPLES_PER_PACKET
    • STREAM_AUTO_TARGET
    • STREAM_SCANLIST_ADDRESS#(0:127)
    • STREAM_ENABLE

    Note that there are other T7 stream configurations.

    How samples are moved from the device to your application - When stream is running, there are two sample buffers to consider: the device buffer and the LJM buffer. The device acquires a scan of stream data at every scan interval according to its own clock and puts that data into the device buffer. At the same time, LJM is running a background thread that moves data from the device buffer to the LJM buffer. At the same time the user application needs to move data from the LJM buffer to the user application. Some definitions and details:

    1. MaxBytesPerPacket: Maximum number of bytes per Modbus TCP packet sent between the device and host. For the T7 the limits are 64/1040/500 bytes for USB/Ethernet/WiFi, respectively.

    2. MaxSamplesPerPacket: A stream data packet has 16 bytes of overhead and each sample needs 2 bytes, so based on MaxByesPerPacket above the maximum number of samples per packet for the T7 is 24/512/242 for USB/Ethernet/WiFi, respectively.

    3. SamplesPerPacket (STREAM_SAMPLES_PER_PACKET): The actual number of samples per USB/TCP packet, as configured by LJM. This will be the smaller of either (ScansPerRead * NumAddresses) or MaxSamplesPerPacket.

    4. SamplesPerTransfer: The number of samples transferred per USB/TCP read call done automatically in the LJM background thread. This sets the interval for how often LJM does a read. An LJM read might consist of multiple USB/TCP packets. This is limited by (ScansPerRead * NumAddresses) and MaxSamplesPerPacket.

    5. ScansPerRead: The number of scans that your software pulls from the LJM stream buffer per call to LJM_eStreamRead. This parameter is used to limit STREAM_SAMPLES_PER_PACKET, so if you want to minimize blocking that might occur due to LJM's stream read thread waiting for data, then set ScansPerRead low. Normally, ScansPerRead is set to a higher value as it is most efficient to move bigger chunks of data less often, but if you want minimum latency between input/output you can set ScansPerRead as low as 1. (For more information on low-latency stream, see the "Low-Latency" section below.)

    Externally clocked stream - Externally clocked stream is when a signal is received on CIO3, for which each rising edge a single scan is triggered. This allows for variable scan rates and synchronized streaming.

    When using externally clocked stream, LJM_eStreamStart's ScanRate should be the fastest scan rate that the externally clocked stream will occur at.

    If externally clocked stream occurs at a variable scan rate or does not occur immediately after calling LJM_eStreamStart, you'll probably need to use an LJM configuration to prevent LJM from throwing an error when scans are not received by LJM within the expected timeframe since LJM normally expects a constant scan rate, and it will throw an error if it does not receive data from the device fast enough. Here are the options for setting LJM's configs for variable speed and/or delayed start streaming, which should be set using LJM_WriteLibraryConfigS:

    - Set LJM_STREAM_SCANS_RETURN to LJM_STREAM_SCANS_RETURN_ALL. This will cause LJM_eStreamRead to return immediately with the error code LJME_NO_SCANS_RETURNED if LJM has not received ScansPerRead scans worth of data. LJM wrappers like LJM Python that throw exceptions instead of returning error codes will throw their language-specific version of LJME_NO_SCANS_RETURNED.

    - Set LJM_STREAM_RECEIVE_TIMEOUT_MS to a safe timeout for your expected stream speeds. This should be the longest expected timeout, plus a small amount extra. If you're not sure how long of a timeout you need, 0 is the infinite timeout and will never time out.

    The configs mentioned above are defined in LabJackM.h.

    Triggered stream - Triggered stream could also be called "delayed start stream". It is when LJM_eStreamStart has been called but stream does not start until a signal is received on FIO0 or FIO1, after which stream continues to collect data as normal.

    To use triggered stream with LJM, you must enable some LJM configurations and also some T7 configurations.

    LJM triggered stream configurations that should be set using LJM_WriteLibraryConfigS:

    - Set LJM_STREAM_SCANS_RETURN to LJM_STREAM_SCANS_RETURN_ALL. This will cause LJM_eStreamRead to return immediately with the error code LJME_NO_SCANS_RETURNED if LJM has not received ScansPerRead scans worth of data. LJM wrappers like LJM Python that throw exceptions instead of returning error codes will throw their language-specific version of LJME_NO_SCANS_RETURNED.

    - Set LJM_STREAM_RECEIVE_TIMEOUT_MS to a safe timeout for how long you expect it to take before stream starts. If you're not sure how long of a timeout you need, 0 is the infinite timeout and will never time out.

    The configs mentioned above are defined in LabJackM.h.

    Burst Stream - Burst stream is when a limited number of scans are collected by the device, after which the device stops streaming. LJM_StreamBurst may be used to automatically perform a burst stream or burst stream may be performed manually using the following steps:

    • Write the desired number of scans to collect to STREAM_NUM_SCANS.
    • Call LJM_eStreamStart
    • Call LJM_eStreamRead until all STREAM_NUM_SCANS have been read or until the return code is STREAM_BURST_COMPLETE (2944)
    • Call LJM_eStreamStop (to clean up memory)

    Auto-recovery Precaution - If auto-recovery is enabled (the default), and there is any risk of auto-recovery happening (typically happens at the highest data rates only), the first channel in the stream scan list should always be an analog input (AIN#). If you only want to stream other channels besides analog inputs and cannot add a dummy analog input because you need maximum speed, then ensure that the first channel in the scan list will never return 0xFFFF as a normal valid reading or see the "Stream Speed" section below to reduce the chances of auto-recovery.

    Auto-recovery mode is entered when the stream buffer on the LabJack device is too full. At that point, the device will discard further scans but will keep track of how many scans have been discarded. Once stream read has caught up and emptied the device stream buffer sufficiently, the device will stop discarding scans, and will send a data packet that reports the number of discarded scans and also has a scan of all 0xFFFF that denotes the border between pre and post auto-recovery data. In the LJM stream buffer that is read by the user's application, LJM inserts the proper number of dummy scans, filled with all -9999.0s, to maintain proper timing of stream data through auto-recovery.

    LJM actually looks at the first value in each scan to detect the border scan. Once auto-recovery starts, LJM watches the first channel in a scan and if it sees 0xFFFF it assumes that is the border scan that marks the start of post auto-recovery data. 0xFFFF is a special reserved value that analog inputs never return under normal circumstances.

    Low-Latency - Low-latency stream is for when you need to move data from the device to the host application as soon as possible after acquisition (i.e. with minimum latency). For example, you might be trying to correlate stream data with the host's clock, or perhaps are doing real-time feedback control.

    To do low-latency stream, set the ScansPerRead parameter of the LJM_eStreamStart function to a small number. This will cause LJM_eStreamRead or the callback of LJM_SetStreamCallback to read smaller amounts more often. However, latency could still be up to 40 ms because LJM transfers data from the device at 25 Hz by default. To improve this, set LJM_STREAM_TRANSFERS_PER_SECOND to a larger number. For the lowest possible latency, you want 1 scan to be transferred at a time from device to LJM and LJM to host application, which can be forced by setting ScansPerRead = 1 and LJM_STREAM_TRANSFERS_PER_SECOND = 999999999.

    Low-latency stream is typically limited to a scan rate of few kscans/second or less due to the increased overhead per scan. This increased overhead can cause the symptoms mentioned in the Stream Speed section below. To get stream latency as low as possible, avoid doing unnecessary work in either the thread that calls LJM_eStreamRead or in the callback set by LJM_SetStreamCallback. File I/O, hardware I/O, and screen updates can all take substantial time.

    Stream Speed - To ensure the host application is able to stream quickly, see our troubleshooting guide for the following situations:

    • If LJM_eStreamRead is returning error 1301 (LJME_LJM_BUFFER_FULL)
    • If LJM_eStreamRead gives many -9999 values in aData

    Reducing Stream Startup Speed

    As of LJM 1.1405: If stream has been successfully started for a given device handle without returning a LJME_USING_DEFAULT_CALIBRATION warning, the next stream start for that device handle will not load the stream calibration. This has been shown to reduce the stream startup time by about 6 milliseconds via USB or 10 or more milliseconds via TCP.

    Example

    [C/C++] Start stream with a scan rate of 10 kHz and 2 channels.

    char ErrorString[LJM_MAX_NAME_SIZE];
    int LJMError;
    const int numAddresses = 2;
    const int aScanList[] = {0, 2}; // AIN0 and AIN1
    const int initScanRate = 10000;
    double scanRate = initScanRate;
    const int scansPerRead = initScanRate / 2;
    double aData[numAddresses * scansPerRead];
    int DeviceScanBacklog;
    int LJMScanBacklog;
    int iteration = 0;
    // Start stream
    // handle from LJM_Open() or LJM_OpenS()
    LJMError = LJM_eStreamStart(handle, scansPerRead, numAddresses, aScanList, &scanRate);
    if (LJMError != 0) {
        LJM_ErrorToString(LJMError, ErrorString);
        printf("LJM_eStreamStart error: %s\n", ErrorString);
    }
    else {
        printf("Stream started at %f Hz\n", scanRate);
    }
    // Read stream
    for (iteration = 0; iteration < 10; iteration++) {
        LJMError = LJM_eStreamRead(handle, aData, &DeviceScanBacklog, &LJMScanBacklog);
        if (LJMError != 0) {
            LJM_ErrorToString(LJMError, ErrorString);
            printf("LJM_eStreamRead error: %s\n", ErrorString);
        }
    
        // Process the stream data in whatever way suits your application
        MyDataProcessingFunction(aData, DeviceScanBacklog, LJMScanBacklog);
    }
    // Stop stream
    LJMError = LJM_eStreamStop(handle);
    if (LJMError != 0) {
        LJM_ErrorToString(LJMError, ErrorString);
        printf("LJM_eStreamStop error: %s\n", ErrorString);
    }

    6 comments

    Any info about what the max scan rate will be given a number of inputs or how large the input buffer can be?

    Scan Rate

    The max scan rate is limited by a few things.

    Firstly, the device has a max sample rate. The T7 is currently able to stream at a 100 kHz sample rate. Sample rates can be converted to scan rates by dividing by the number of channels (NumAddresses). So, if you have 4 channels, the maximum scan rate is 25 kHz (100 / 4 = 25).

    The max scan rate can also be limited by the host computer's ability to read data from the device. Also, the T7 Pro's wireless connection cannot stream data as fast as USB or Ethernet.

    Buffers

    There are 2 buffers involved when streaming. There is one buffer on the device and one buffer within LJM. Information on the T7's stream buffer can be found on the stream-mode page of the T7 datasheet. Especially, see STREAM_BUFFER_SIZE_BYTES. (And don't forget to convert between scans, samples and bytes. Each sample is 2 bytes.)

    The LJM buffer's size is set by default to have a 20 seconds of buffer time, based on the scan rate and the number of channels in stream.

    Hi

     

    I am trying to sample 200ms at maximum sampling rate at 4 channels. 

     

    What settings to use?

    If you want samples to be collected every 200ms, the ScanRate will be 5. (1000ms / 200ms = 5 Hz)

    If you want to collect samples at the maximum scan rate, the approximate maximum sample rate of the T7 is 100 kHz. Since (ScanRate = SampleRate / NumAddresses), the max ScanRate would be approximately 25 kHz for 4 channels.

     

    Whichever scan rate you meant, you should pass NumAddresses as 4 and ScanList as an array of those 4 channels. I recommend setting the ScansPerRead to (ScanRate / 2).

    Please see the T7 Datasheet's Stream Mode documentation for more information:

    http://labjack.com/support/datasheets/t7/communication/stream-mode

     

    When I run eStreamStart (using the Python LJM wrapper on Linux), the first stream start/read/stop cycle works, but when I try to start the stream a second time, I get a LJME_RECONNECT_FAILED exception.

    After getting this exception, if I try to start the stream again, I get a STREAM_IS_ACTIVE exception.

    If I then try to eStreamRead, I get an error message saying that the stream has not been initialised. Running eStreamStart again gets the same RECONNECT_FAILED/STREAM_IS_ACTIVE combination.

    At first it seemed to be failing at sampling rates above 10000 (only one channel being sampled), but now it seems to be happening below 10000 as well.

    I can run the same script on OS X without error.

    Download and install the latest Linux driver (currently v1.0707) from here and see if that helps:

    http://labjack.com/support/ljm

    Note that the main 32-bit/64-bit Linux installs are built from CentOS but are for all Linux distributions. Also, if getting the STREAM_IS_ACTIVE after installing the latest driver, power cycle your T7.