Measurement Studio for VC++

cancel
Showing results for 
Search instead for 
Did you mean: 

Asynchronously Serial Communication with CNiVisa

System: Measurement Studio 7.1 with Visual C++.net (Version 2003)
 
 
I would like to use the asynchronously read() to get data from RS232 (com-port 1), but it doesn't work.
 
I varied the threshold level in MAX (Measurement &Automation Explorer), that means the Minimum Async Transfer between 16 and 1000 Bytes and I tried to read 20 to 700 Bytes.
 
If I read less bytes than the threshold, the read() works synchronously. The dialog is blocked, until all bytes are in the buffer.
 
If I try to read more bytes than the threshold, I get some "undefined runtime errors".
 
Is something wrong with my code (s. below) ?
Does anybody know, what to do, to get the asynchronously read() to work, that means that it returns immediately, so that the program can react to user input during the data reading ?
 
Thanks in advance
 
       Hannes
 
 
 
 
My code snippets:
 
 

////////////////////// MyDialog.h

class

CMyDialog : public CDialog

{

..........

public

:

ViStatus OnMyRead( CNiVisaEvent& event );

protected

:

CNiVisaSession *m_Session;

CNiVisaJobId m_ReadJob;

public

:

afx_msg

void OnBnClickedRead();

...........

};

 

////////////////////// MyDialog.cpp

........

BOOL CMyDialog::OnInitDialog()

{

CString csName = "ASRl1::INSTR";

// COM-Port 1

CNiVisaEventHandlerId eventId;

m_Session =

new CNiVisaSession( csName, VisaNoLock, 5000 );

m_Session->SetAttribute( VisaTimeout, VisaTimeoutInfinite );

m_Session->SetAttribute( VisaSerialEndIn, (uInt16)VisaEndNone );

m_Session->SetAttribute( VisaTerminationChar, (uInt16)0 );

m_Session->SetBufferSize( VisaSerialInputBuffer, (uInt32)5000 );

// Event-Handler

m_Session->InstallEventHandler( VisaEventIoComplete,

*

this,

OnVisaEventHandler(CMyDialog, OnMyRead),

eventId );

m_Session->EnableEvent( VisaEventIoComplete, VisaHandler );

return true;

}

 

// Start Asynchron-Read

void

CMyDialog::OnBnClickedRead()

{

//m_Session->Read( (ViBuf)m_cBuffer, 20, m_ReadJob ); // 20 Bytes

m_Session->Read( (ViBuf)m_cBuffer, 700, m_ReadJob );

// 700 Bytes

}

 

// Callback-Handler for Asynchron-Read

ViStatus CMyDialog::OnMyRead( CNiVisaEvent& event )

{

// process Read()-Data from m_cBuffer

return VisaSuccess;

}

...............

 
 
0 Kudos
Message 1 of 8
(4,139 Views)

I found out, that the current problem is caused inside my Event Handler by the following statements:

// Callback-Handler for Asynchron-Read

ViStatus CMyDialog::OnMyRead( CNiVisaEvent& event )
{

     // process Read()-Data from m_cBuffer
     .....

     // display the results
     UpdateData( false );
     m_slideLager11.SetValue(m_cZeichen);

     return VisaSuccess;
}

After processing the received data, I would like to update the dialog controls to show the results (slider control ...).
Why do the statements UpdateData() and m_slide.SetValue() cause runtime errors ?
If I make the controls update by this statements outside of the Event Handler it works.
Is there any possibility to make the update inside of the Event Handler ?

Another problem:
The asynchronously read() returns immediately inside of the dialog. But if I close the dialog, before the job is done, the program is blocked (for about 15 seconds). I cannot make any input (choose another dialog ...) and I cannot close the program (no reaction if I try).
I supposed, the asynchronously job is killed, if I use the Terminate()-function in the dialogs destructor like this:

CMyDialog::~CMyDialog()
{
     ......

     m_Session->Terminate( m_ReadJob );

     delete m_Session;

}

It doesn't work. With or without the Terminate()-statement, the program is blocked after closing the dialog before the asynchronously job is done. I tried also inside of the OnCancel()-function, but without success.
Do you have any idea why ?
Does anybody have some small code example which shows completely the asynchronously read() from the beginning to the correct termination, so that the program is not blocked in any way ?

 

Thanks a lot

Hannes

 

0 Kudos
Message 2 of 8
(4,137 Views)

Can you tell me what runtime error the calls to UpdateData and SetValue are causing?

User interface controls typically must be accessed only from the thread on which they were created. When you create an event callback ofr VISA, it is very unlikely that that callback occurs on the UI thread - so updating controls from within it is not likely to work. The Measurement Studio C++ controls are designed so that, by default, they ARE accessible from multiple threads. The call to UpdateData, though, is occuring on the dialog class - which has no such guarantee. This might be the cause of the problem. Why are you calling UpdateData?

Also, in order to properly handle asynchronous reads and writes,you need to enable IO Completion events and register and appropriate callback for the event - this is the event that fires when the read or write completes. The JobId that the Read method returns is used to identify a particular read async event that completed.

The asynchronous read also tries to read into the buffer you supply when you call read - if that buffer is being deleted before the asynchronous operation terminates, you're going to run into some problems as well - for instance, if the lifetime of that buffer is shorter than the lifetime of the asynchronous operation. It appears from your code that you're using a member variable of the dialog box - so if the dialog is closed and destroyed while an async operation is still running, that would be a bad thing.

When you say that the call to Terminate doesn't work, can you tell me what IS happening? Are you getting an exception?

I'm having a hard time figuring out where to point you on this, because I don't think I really understand the architecture of your application - is all of this VISA serial IO going on in a dialog box that is launched from your main application window? If so, perhaps we need to separate the buffer, session, and async operation lifetime management from the lifetime of the dialog box.

0 Kudos
Message 3 of 8
(4,127 Views)

Hallo Glenn,

thanks for your quick answer.

I start at the end of your questions:

The architecture of my test application is very simple. I have created a doc / view project with only one dialog, which is launched from the main window (by menue button). In this dialog, I would like to receive serial data, which are continuously coming. It is necessary to get data blocks in real time (9600 Baud). Between the blocks the data processing and display can be made.
After closing the dialog, I cannot close the program properly (even not with the call to Terminate), if the asynchronous job is not finished. I get no exception, but it just happens nothing for a long time of about 15 seconds. Then the program is closed.

Maybe this architecture is not the best to handle my application ?
I started with that simple dialog and the doc / view architecture because I thought, that should be an easy test environment.
In the final program I need sevaral dialogs to generate several views of the continuously incoming data.

I have an old program, which was developd in LabWindows and worked very fine. I used the "InstallComCallback"-function. This Handler can be set to a threshold value of incoming bytes. If more bytes are in the serial buffer, the callback function is triggered. In that function, the data processing, display and storage is done. After completion, I flush the serial buffer and the callback function is triggered the next time after receiving more bytes than the threshold value. Between the callback triggers, the program is not blocked. The user can change the scaling of diagram controls for example. Closing of the program is also no problem.

I'm looking for a mechanism like that in Measurement Studio !
The data receiving and storage should always work in the background. Meanwhile the user should have the possibility to make inputs to the program (choose several views and so on). The data processing, display and storage must go automatcally without user action.

I'm calling UpdataData() to update some Edit-Controls with new values.
The runtime error also occurs by updating the slider-control (m_slide.SetValue() 😞
"Debug Assertion Failed, File winocc.cpp, line 374" :   ASSERT(m_pCtrlSite != NULL);

 

Regards   Hannes

0 Kudos
Message 4 of 8
(4,122 Views)
So it definitely seems like you need to separate the session and buffer lifetime from the lifetime of the dialog -
I think the best thing to do would be to use the VisaEventSerialAnyCharReceived event, and inside the callback, check the VisaSerialBytesAvailable attribute. When the bytes available are greater than or equal to what you need to read, perform the read. Is there are reason that this approach would not work for you?
0 Kudos
Message 5 of 8
(4,106 Views)

Hallo Glenn,

thanks for your answer. Meanwhile I got the program to work with lifetime management between the OnCancel()-function and the EventHandler-Callback.

I still have one problem:
I only can finish the program, if there are data coming until the callback is finished. Inside the callback there are several synchronously reads to follow the continuously incoming bytes. The "SerialAnyCharReceivedEvent" is only used as a trigger to start the callback. If the data stream is stopped during a read, the callback will never end. I cannot work with any timeout condition, because the data stream can be stopped for a "long time" (2 days...) and after the data are coming again, the program must continue without any user input. Therefore I set the Timeout to "infinite". On the other hand, it must be possible to finish the program, if there are no data coming.

Therefore I think, I need the asynchronously read. The read must be terminated, if the user wants to finish the program before all data bytes of the read are received.

As I told you before, I tried to terminate the asynchronously read job, but it didn't work.

Can you tell me, how to terminate the asynchronously read job inside of the dialog (ore anywhere else) ?
Do you have some example code, that shows what to do ?

 

Regards

Hannes

0 Kudos
Message 6 of 8
(4,098 Views)
We don't have any examples for asynchronous IO for the Measurement Studio C++ classes. Your general approach is sound - to kill the asynchronous job, you would call Terminate and pass in the jobId returned from the ReadAsync method. You can also pass in NULL for the jobId to kill all async operations on the session.
 
I still am not clear what IS happening in your code when you call Terminate. What is the status code returned from the call? Terminate can throw an exception under some circumstances - is it possible that you're getting an exception thrown there, and not catching it?
0 Kudos
Message 7 of 8
(4,094 Views)

I will check that in future.

In the moment, I changed my application to use the VisaBytesSerialAttribute in the way you suggested.

That works properly in the moment.

 

Thanks for your help

Hannes

0 Kudos
Message 8 of 8
(4,085 Views)