| | |
reading from serial port way too slow (C++)
Please support our C++ advertiser: Intel Parallel Studio Home
Thread Solved |
•
•
Join Date: Dec 2008
Posts: 22
Reputation:
Solved Threads: 0
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:
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
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 2:02 pm.
•
•
Join Date: Dec 2008
Posts: 22
Reputation:
Solved Threads: 0
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)
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 4:55 am.
•
•
Join Date: Dec 2008
Posts: 22
Reputation:
Solved Threads: 0
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.
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.
•
•
Join Date: Dec 2008
Posts: 22
Reputation:
Solved Threads: 0
Thanks.
I'll try it on Monday, report to you then
I'll try it on Monday, report to you then
•
•
Join Date: Dec 2008
Posts: 22
Reputation:
Solved Threads: 0
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.
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.
![]() |
Similar Threads
- SpeedUp Your Window XP Never Than Before (Windows tips 'n' tweaks)
- reading data using serial port (Visual Basic 4 / 5 / 6)
- memory management in wndows 2000 (Windows NT / 2000 / XP)
- need suggestion on this project (Visual Basic 4 / 5 / 6)
Other Threads in the C++ Forum
- Previous Thread: Set the include path
- Next Thread: Help with saving/loading system.
| Thread Tools | Search this Thread |
api array based beginner binary c++ c/c++ calculator char char* class classes code compile compiler console conversion count delete deploy desktop directshow dll download dynamic dynamiccharacterarray email encryption error file forms fstream function functions game givemetehcodez google graph gui homeworkhelp homeworkhelper iamthwee ifstream input int integer java lib linkedlist linker linux list loop looping loops map math matrix memory news node numbertoword output parameter pointer problem program programming project python random read recursion recursive reference return rpg sorting string strings struct temperature template templates test text text-file tree unix url variable vector video visualstudio win32 windows winsock word wordfrequency wxwidgets






