RSS Forums RSS

reading from serial port way too slow (C++)

Please support our C++ advertiser: Programming Forums
Thread Solved
Reply
Posts: 19
Reputation: GadiK is an unknown quantity at this point 
Solved Threads: 0
GadiK GadiK is offline Offline
Newbie Poster

reading from serial port way too slow (C++)

  #1  
Dec 3rd, 2008
Hey,
I'm having a problem reading from a device attached to my serial port.

I have a big application which uses a thread to read from the serial device and writes the data to a log file. The device is set to transmit data at 500Hz, which means that my thread receives data of 14 bytes every 2 miliseconds.
The baud rate is set to 115200 and actually everything is working pretty fine accept it takes too long.

I'm using a polling method, meaning I check if there are enough bytes in the buffer and I read them. After the device stops transmitting I read from the buffer until it's empty and the thread ends.
The problem with this is that I'm constantly polling the buffer which results in 100% CPU usage. Since we're talking about a thread which is a part of a much bigger application this CPU business is out of the question.

Thus, I'm forced to use the Sleep() function. And here the problem begins:
  • without Sleep: After the device stops transmitting the thread empties the buffer almost immediately and the thread ends in a matter of seconds.
  • with Sleep: After the device stops transmitting the thread takes from 5 minutes to 35 minutes to empty the buffer (depends on the transmission duration).

Minutes are not the timing I had in mind when I wrote this thread. I tried to change the thread priority but it didn't work. I also tried to use event driven programming but it's too slow for my thread.

I could really use your help, any suggestion would be welcomed.

Thank You,
Gadi
Last edited by GadiK : Dec 3rd, 2008 at 1:02 pm.
AddThis Social Bookmark Button
Reply With Quote  
Posts: 55
Reputation: nmaillet is an unknown quantity at this point 
Solved Threads: 11
nmaillet nmaillet is offline Offline
Junior Poster in Training

Re: reading from serial port way too slow (C++)

  #2  
Dec 3rd, 2008
I'm not very experienced with threads in C++, but from what you said, it shouldn't make a difference in the amount of time it takes to empty the buffer. Have you tried it on another computer? And how long are you setting it to sleep for? Also, some code might help.

Nick
Reply With Quote  
Posts: 19
Reputation: GadiK is an unknown quantity at this point 
Solved Threads: 0
GadiK GadiK is offline Offline
Newbie Poster

Re: reading from serial port way too slow (C++)

  #3  
Dec 4th, 2008
Hi,
I didn't try on another computer yet.

The Sleep() function is set to 1 milisecond. It is the minimum, so I tested to see if a "longer" sleep would help me - it didn't, it took longer.

Here's the thread:
(I'm using a SerialCom object that somebody else wrote. The function ReadString() uses ReadFile() and returns FALSE if operation didn't succeed. Also, I used AfxBeginThread() to start this thread)
unsigned int CRmi_demoDlg::GetADISData(void *Sender)
{
	CRmi_demoDlg* pSender = NULL;
	pSender = (CRmi_demoDlg *)Sender;
	char filename[60];
	int rd_iter, i;
	GetSystemTime(&st);	
	//------------------------Files--------------------
	
	//open the serial device com port 
	pSender->ADISDevice.Open("COM8");
	
	//setting buffer size for serial device to avoid buffer overrun
	if (!SetupComm(pSender->ADISDevice.hCom,0x00F00000,64))
		myprintf("\nCouldn't set device buffer size!");

	GetCommProperties(pSender->ADISDevice.hCom,&commProp);
	//myprintf prints to a console which logs the threads activities
        myprintf("\nADIS buffer size: %d bytes",(int) commProp.dwCurrentRxQueue);
	
	//setup the serial port
	pSender->ADISDevice.Setup(115200,8,0,1);
	
	
	//if port isn't open;
	if (pSender->ADISDevice.hCom == INVALID_HANDLE_VALUE) {
		pSender->ADISDevice.Close();
		AfxMessageBox((CString)"Couldn't get device handle");
		return 0;  
	}
	
	sprintf_s(filename,60,"test%d_ADIS_%d.%d.%d_%d.            %d.%d.txt",test_num,st.wDay,st.wMonth,st.wYear,st.wHour+3,st.wMinute,st.wSecond);
		
	// open the log file
	ofstream logfile(filename);
	
	
	if ( !logfile.is_open() ) {
		AfxMessageBox((CString) "Couldn't open LOG file!");
		return 0;
	}

	CreateADISFileHeader(logfile);
	//------------------------Sampling--------------------
	
         //clear com before working with it	
         pSender->ADISDevice.clearCom();  
	
        if(pSender && pSender->initialized )
	{
		 char finger_byte[14]="0";
		 short finger_word, index;
		 short short_lowbyte=0;
		 short short_highbyte=0;
		 short flags = 0;
		 short data_error;		//keeps tabs of bit errors
		 bool r_sent = false;
		
		pSender->ADISDevice.WriteString("r",1);  //send "reset" command
		pSender->ADISDevice.WriteString("s",1); //send "start" command
		while ( pSender->ADISDevice.getNumBytesInQue() < 1 ) {};	//wait for data to come into the buffer
		myprintf("\nReceiving Data");
		
		//stop running if no more data in buffer or GUI closed
                while( pSender->initialized && (!r_sent || pSender->ADISDevice.getNumBytesInQue() > 0) )	
		{
			if ( !pSender->is_sample )
			{
				//if stop button pressed tell the ADIS to stop sending data
                               if ( !pSender->ADISDevice.WriteString("r",1) ) myprintf("\nCouldn't write to ADIS"); 
				if (!r_sent) myprintf("\nStop button pressed");
				r_sent = true; //r_sent flags that the device was told to stop sending data
			}
			GetSystemTime(&st);
			//first two bytes of every iteration are 0x55
			if ( pSender->ADISDevice.getNumBytesInQue() >= 2 )
			{
				pSender->ADISDevice.ReadString(finger_byte, 2);
			}
			else if (!r_sent) continue;		//loop only if ADIS stil working
			
			
			if ( (finger_byte[0] != finger_byte[1]) || (finger_byte[0] != 0x55) )
			{
				AfxMessageBox((CString)"Out of sync!");
				logfile.close();
				logfile2.close();
				pSender->ADISDevice.Close();
				AfxEndThread(0);
				return 0;
			}
			//reading iteration = 15 times, each time 14 bytes
			for (rd_iter=0; rd_iter < 15 ; rd_iter++)
			{
				data_error = 0;
				logfile << setw(5) << setfill(' ') << st.wHour+3 << ", " 
						<< setw(7) << setfill(' ') << st.wMinute << ", " 
						<< setw(7) << setfill(' ') << st.wSecond << ", " 
						<< setw(7) << setfill(' ') << st.wMilliseconds << ", ";
				
                               // wait untill there is enough information in the buffer unless ADIS stopped 
                               while ( pSender->ADISDevice.getNumBytesInQue() < 14 && !r_sent)	{}	[
				
				Sleep(1);
				if ( !pSender->ADISDevice.ReadString(finger_byte, 7*2) ) 
				{
					//if no more data in buffer end loop and make sound
                                        myprintf("\nCouldn't read from ADIS");
					MessageBeep(MB_ICONASTERISK);
					Sleep(500);
					MessageBeep(MB_ICONASTERISK);
					Sleep(500);
					MessageBeep(MB_ICONASTERISK);
					Sleep(500);
					break;
				}
				
                                //processing the received 14 bytes
                                //and writing them to the log file
                                for (i=0; i < 7*2 ; i++) 
				{
					short_highbyte=(( short)finger_byte[i]) & 0x00FF;
					short_lowbyte=(( short)finger_byte[++i]) & 0x00FF;
					finger_word=0;
					finger_word=short_highbyte*256+short_lowbyte;
					
					if (i == 1)  //first word is always index
					{
						finger_word = ( short) finger_word/64;  //shift right 6 times
						finger_word = finger_word & 0x000F;
						index = finger_word;
					}
					else  
					{
						flags = 0xC000 & finger_word;  
                                                //contracting 2 msb which are NewData 
                                                //and ErrorAlarm the other 14 bits are data
						finger_word <<= 2;
						finger_word >>= 2;	//with bit extraction because its signed short
											
						// put '1' at the bit corresponding to processed data 
                                                //for example: XAccl error is at bit number 5
						// ZGyro error is at bit number 0
						data_error = data_error << 2;
						flags = flags >>14;	//without bit extraction because its unsigned 
                                                                                   short
						data_error |= flags;
					}


					logfile << setw(10) << setfill(' ') << finger_word << ", ";
				}
				
				
				logfile << setw(10) << setfill(' ') << data_error << endl;
			}
		}
	}
	myprintf("\nNo more data in buffer");
	pSender->ADISDevice.WriteString("r",1);  //send "reset" command
	while (pSender->ADISDevice.getNumBytesInQue() > 0) pSender->ADISDevice.clearCom();
	pSender->ADISDevice.Close();
	
	if( logfile.is_open() )logfile.close();
	AfxEndThread(0);
	return 0;
	
}
/*----------------------------End of GetADISData---------------------------------------------*/
Last edited by GadiK : Dec 4th, 2008 at 3:55 am.
Reply With Quote  
Posts: 19
Reputation: GadiK is an unknown quantity at this point 
Solved Threads: 0
GadiK GadiK is offline Offline
Newbie Poster

Re: reading from serial port way too slow (C++)

  #4  
Dec 4th, 2008
Another development:
If I set the following conditions I am able to run the entire application with 62% CPU usage (where without the above thread the main application uses 52%):
SetPriorityClass(HIGH_PRIORITY_CLASS);
SetThreadPriority(THREAD_PRIORITY_HIGH);
And I set the Sleep() argument to be 0.01 - meaning I call it like this: Sleep(0.01).

If I don't set the priorities and only use the Sleep(0.01) it doesn't work. If I only set the priorities but use Sleep(1) it doesn't work.

I don't know how it is possible that the Sleep() function receives a float argument since it should get DWORD arguments, but it does.
I get a warning that I am sending a float instead of DWORD so I gather that a casting from float to DWORD occurs, however I tried to use Sleep(0) and it gave me 90% CPU usage.

This is still not the solution I am seeking. Since the high priorities may affect the performance of the rest of the application, and since the purpose of the application is to control a small vehicle, I wouldn't want my small thread to cause an accident.

P.S. I've changed the thread creation to CreateThread() instead of AfxBeginThread() so that I could get a HANDLE on the thread.
Reply With Quote  
Posts: 5,126
Reputation: Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute Salem has a reputation beyond repute 
Solved Threads: 633
Colleague
Salem's Avatar
Salem Salem is offline Offline
Void main'ers are DOOMed

Re: reading from serial port way too slow (C++)

  #5  
Dec 4th, 2008
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
UK Voter? Please send a message to Incapability Brown and the rest of Zanu-Labour
Up to 8Mb PlusNet broadband from only £5.99 a month!
Reply With Quote  
Posts: 19
Reputation: GadiK is an unknown quantity at this point 
Solved Threads: 0
GadiK GadiK is offline Offline
Newbie Poster

Re: reading from serial port way too slow (C++)

  #6  
Dec 4th, 2008
Originally Posted by Salem View Post
Another approach to consider.
http://msdn.microsoft.com/en-us/libr...83(VS.85).aspx

Thanks.
I'll try it on Monday, report to you then
Reply With Quote  
Posts: 19
Reputation: GadiK is an unknown quantity at this point 
Solved Threads: 0
GadiK GadiK is offline Offline
Newbie Poster

Re: reading from serial port way too slow (C++)

  #7  
Dec 17th, 2008
okay, just wanted to let you know that I've worked things out.
Your tips were helpful so thank you very much.

I'll explain what I did so that others with a similar problem would try it.
Instead of trying to capture every data package that is sent, I waited 'till there were 5 packages and then read all of them into my working buffer (which was basically an array of chars with the appropriate size). After I rewrote my thread to work like this, the CPU usage dropped down to almost none.
I tried using my thread reading a single package at a time, and it worked great!

So, again, thanks everyone
And have a good and happy new year.
Reply With Quote  
Reply

Only community members can participate in forum threads. You must register or log in to contribute.



Similar Threads
Other Threads in the C++ Forum
Views: 970 | Replies: 6 | Currently Viewing: 1 (0 members and 1 guests)

 

Thread Tools Display Modes
Forums | Blogs | Tutorials | Code Snippets | Whitepapers | RSS Feeds | Advertising
All times are GMT -4. The time now is 11:01 pm.
Newsletter Archive - Sitemap - Privacy Statement - Acceptable Use Policy - Contact Us
Forum system based on vBulletin Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
©2003 - 2008 DaniWeb® LLC