LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

TSQ

Hy,

I'm new in LabWindows and have to work with multithreads.

I've got no user interface and I like to aquire continously data from my system. (I generate signals with the PXI 4461 ao0 und ao1 and aquiring signals with the PXI 4462 ai0 and ai1).
I want to use a thread-safe-queue. So that I can aquire data at the same time as I'm calculate with them and write them to a textfile.

Thanks for help.

Here my code.
0 Kudos
Message 1 of 7
(5,077 Views)

Hi kleyh,

Since you are just starting out using LabWindows/CVI, the best place to begin is to look at our examples. In your case, you will be doing some multithreading and thus using our Utility Library (which contains Thread Pools, Thread Safe Queues, Thread Safe Variables, Thread Locks, Thread Local Variables, etc). Check out the <CVI>\samples\utility\Threading\ folder which has a good variety of examples including a ThreadSafeQueue example.

Hope this helps!

Best Regards,

Jonathan N.
National Instruments
0 Kudos
Message 2 of 7
(5,061 Views)
Hy Jonathan,

thanks for your answer. I already had a look at several examples and I also read the availables pdfs of NI.
Now I had a look at your examples but I've got still the same problem.

Here an extract of my code:

int queue;
volatile int ende = 0;

void main()
{
    init();
    ausgabe();
   
    CmtNewTSQ();
    CmtInstallTSQCallback();->void CVICALLBACK queueReadCallback
    CmtScheduleThreadPoolFunction();->int CVICALLBACK messung
  
     quit();
   
    CmtWaitforthreadPoolFunctionCompletion();
    CmtReleaseThreadPoolFunctionID();
    CmtUninstallTSQCallback();
    CmtDiscardTSQ();
}

void init()
{
    //AnalogOut PXI 4461 ao0 und ao1
    DAQmxCreateTask("DAQAusgabe", &taskOut);    
    DAQmxCreateAOVoltageChan(taskOut,"DSA2In2Out/ao0","SpannungAusgang_0",-10, 10,DAQmx_Val_Volts,"");
    DAQmxCreateAOVoltageChan(taskOut,"DSA2In2Out/ao1","SpannungAusgang_1", -10, 10, DAQmx_Val_Volts, "");
   
    DAQmxSetChanAttribute(taskOut,"SpannungAusgang_0",DAQmx_AO_TermCfg,DAQmx_Val_Diff);   
    DAQmxSetChanAttribute(taskOut,"SpannungAusgang_1",DAQmx_AO_TermCfg,DAQmx_Val_Diff);
   
    DAQmxCfgSampClkTiming(taskOut,"",FOUT,DAQmx_Val_Rising, DAQmx_Val_ContSamps,NOUT);
    DAQmxSetTimingAttribute(taskOut,DAQmx_RefClk_Src,"PXI_Clk10");   
    DAQmxSetWriteAttribute(taskOut,DAQmx_Write_RegenMode,DAQmx_Val_AllowRegen);

    //AnalogIn PXI 4462 ai0 und ai1
    DAQmxCreateTask("DAQMessung", &taskIn);   
    DAQmxCreateAIVoltageChan(taskIn,"DSA4In/ai0","spannung_0",DAQmx_Val_Diff,-10,10,DAQmx_Val_Volts, "");
    DAQmxCreateAIVoltageChan(taskIn,"DSA4In/ai1","spannung_1",DAQmx_Val_Diff,-10,10,DAQmx_Val_Volts, "");   

    DAQmxSetChanAttribute(taskIn,"",DAQmx_AI_Coupling,DAQmx_Val_AC);
    DAQmxSetChanAttribute(taskIn,"",DAQmx_AI_Coupling,DAQmx_Val_AC);   

    DAQmxCfgSampClkTiming(taskIn, "",FIN,DAQmx_Val_Rising, DAQmx_Val_ContSamps,NIN);
    DAQmxSetTimingAttribute(taskIn,DAQmx_SyncPulse_Src,"/DSA2In2Out/SyncPulse");
    DAQmxSetTimingAttribute(taskIn,DAQmx_RefClk_Src,"PXI_Clk10");   
    DAQmxCfgAnlgEdgeStartTrig(taskIn,"spannung_0",DAQmx_Val_RisingSlope,0);
}

void ausgabe()
{
...
    DAQmxWriteAnalogF64(taskOut,NOUT,1,10.0,DAQmx_Val_GroupByChannel,analogOut,&writtenOut,NULL);
}

void CVICALLBACK queueReadCallback (int queueHandle, unsigned int event, int value, void *callbackData)
{
...
    CmtReadTSQData(queue,data,anz*NIN/2,TSQ_INFINITE_TIMEOUT,0);
}
i
nt CVICALLBACK messung (void *functionData)
{
...
    while(!ende)
    {
    DAQmxReadAnalogF64(taskIn,NIN,10.0,DAQmx_Val_GroupByScanNumber, analogIn,anz*NIN,&read,NULL);
    CmtWriteTSQData(queue,analogIn,anz*NIN,TSQ_INFINITE_TIMEOUT,NULL);
    }
}

void quit()
{
    printf("Acquiring samples continuously. Press any key to interrupt\n");
    getchar();  
    ende = 1;               
}

And here an extract of a pdf:
Multithreading in LabWindows/CVI, July 2003, page 9
"Generally, a secondary thread in the application acquires the data while the main thread
reads the data when it is available and then analyzes and/or displays the data."


int queue;
int panelHandle;

int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0)
        return -1; /* out of memory */
    if ((panelHandle = LoadPanel(0, "DAQDisplay.uir", PANEL)) < 0)
        return -1;
   
    /* create queue that holds 1000 doubles and grows if needed */
    CmtNewTSQ(1000, sizeof(double), OPT_TSQ_DYNAMIC_SIZE, &queue);
    CmtInstallTSQCallback (queue, EVENT_TSQ_ITEMS_IN_QUEUE, 500, QueueReadCallback,0, CmtGetCurrentThreadID(), NULL);
    CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE,DataAcqThreadFunction, NULL, NULL);
    DisplayPanel (panelHandle);
    RunUserInterface();
    . . .
    return 0;
}

void CVICALLBACK QueueReadCallback (int queueHandle, unsigned int event, int value,void *callbackData)
{
    double data[500];
    CmtReadTSQData (queue, data, 500, TSQ_INFINITE_TIMEOUT, 0);
}

int CVICALLBACK DataAcqThreadFunction (void *functionData)
{
    while (!quit)
    {
        Acquire(. . .);
        Analyze(. . .);
    }
    return 0;
}

I don't really see any differences. The examples only show how to plot the data but I like to save them or calculate with them.

Can you help me?

Thanks a lot.
Salutation, Heike
0 Kudos
Message 3 of 7
(5,022 Views)
Hi Heike,

I am still somewhat confused as to what your real problem is.  Do you need suggestions on the appropriate way to set up a multithreading app? Are having difficulty understanding how the thread safe queue's work? Please elaborate some.

The comment you quoted from our PDF file is basically saying that typical applications have a main UI thread and another thread usually devoted to data acquisition and analysis.  The main UI thread might read and display the data (from the TSQ) while the other thread gathers the data, does some analysis on it and then writes that data to the queue.  In the snippet you posted from our documentation, the QueueReadCallback is executed in the main UI thread (which was chosen by calling CmtGetCurrentThreadID which returns the ID to the current thread which in this case is the main UI thread). 

The
DataAcqThreadFunction is executed in a seperate thread. This thread will read, analyize, and then write the data to the queue.

Does this help any?

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 4 of 7
(4,994 Views)
Hy Jonathan,

I’ve got several problems.

One problem is that the TSQ doesn’t work.

Whence the queue knows to read the data from?
I copied the example of the pdf and wrote into the acquire function to read the data from the PXI card (DAQmxReadAmalog64) and to write them to the queue (CmtWriteTSQData).
The queueReadCallback function should read the data from the queue and write them to a txt-file

Now I acquire continuously data from the PXI card, but my txt-file rest empty. Why?

I tried the program also with calling ProcessSystemEvents () at different locations. And without the CmtWriteTSQData () function.

Here my thoughts.
I want to write a program with the following features to adjust an extern system without a gui:
•    the PXI card writes continuously data to an extern system (DAQmxWriteAnalog64)
•    the program reads continuously data from an extern system (DAQmxReadAnalog64)
•    the PXI card set an event, when the buffer is full (DAQmxRegisterEveryNSamplesEvent)
      -> the argument “uInt32 options” is set to 0, so that the called function is executed in an own DAQ thread
•    the read data are registered in a pool/ array -> (CmtWriteTSQData)
•    when the data are available the program evoke an event
•    a new thread is called, where the data are read from the pool and are manipulated -> (CmtReadTSQData)
•    the manipulated data changing the output-Array
•    and all data are written to a txt-file (ArrayToFile, fprint)
The annotations in the brackets are how I would write the program. But like this it doesn’t work.

I hope you understand now my intention.

Have you further documentation to threads, multithreading or TSQ? I already read everything what is available on the NI website inclusive example codes.

Can you show me how to structure or build the code so that it meets my whishes?
Thanks a lot.

Salutation, Heike

0 Kudos
Message 5 of 7
(4,975 Views)

Hi Heike,

 

The callback function for the TSQ will be called when then event you specify occurs and the threshold value you specify is exceeded.  For example, with TSQ's, there are 3 possible events which are: EVENT_TSQ_QUEUE_SIZE, EVENT_TSQ_ITEMS_IN_QUEUE, and EVENT_TSQ_SPACE_FREE. In the example you posted, the event you are waiting on is the EVENT_TSQ_ITEMS_IN_QUEUE. This event will be generated when a thread writes items to the TSQ and when the number of items in the queue after the new items is added is greater than or equal to the threshold value. In the example, the threshold value was 500. 

 

Now, there is a section in the help under the CmtInstallTSQCallback function that talks about a scenario when you might have more data in the queue than the threshold value. Read that section (it’s talked about in the event parameter) as it’s very important.

 

Now, if you are thinking that your TSQ callback is not getting fired, place breakpoints in your TSQ callback to make sure of that. If the breakpoint is never hit, then you know something is wrong. If the breakpoint is hit, then step through your code to make sure you are getting the correct data and writing to a file. 

 

The overall structure of setting up your program was discussed in my earlier posts. It’s a high level view but the typical approach and you seem to be following the correct layout. Since I am not on the PXI or DAQ teams, I wouldn’t' feel comfortable giving you architecture advice on those specific areas so you might want to post in those specific forums.

 

In your case, breakpoints would be the best troubleshooting option which will tell you if the condition you set up for you TSQ callback is ever occurring. You could also put in DebugPrintf statements in that callback as well to help out. 

 

Hope this helps!

 

Best Regards,

Jonathan N.
National Instruments
0 Kudos
Message 6 of 7
(4,966 Views)
Can you do this same thing without LabWindows/CVI,?
I have a VB aplication that works fine with simulated data. I need to get data from DACmx (pic_4462) into Visual Studio 2005 express. Where do I go for help?
0 Kudos
Message 7 of 7
(4,841 Views)