Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Help Reading data from COM port using Win 32 API 2

Status
Not open for further replies.

cplsplsprogrammer

Programmer
Apr 18, 2005
42
US
Hello All, I am trying to read data from a serial port in C using Win32 API. I created a thread from the main program which is an NT service and opened the port. Everything is working fine till opening the port and now I tried to read the data from COM port using ReadFile() in overlapped mode. The ReadFile always fails, I can see that the characters are arriving as I used WaitCommEvent() and WaitforSingleObject() to wait till a character arrives. Can anyone help me with this. I am pasting my function below...... Can anyone please tell me where i am doing wrong?

DWORD CommThreadProc( LPDWORD param )
{

OVERLAPPED comReader = { 0 };
BOOL fWaitingOnRead = FALSE;
char * lpBuf = "";
DWORD dwRead = 0; // bytes actually read
BOOL Success;
FILE* FilePtr;
DCB dcb = {0};
DWORD dwCommEvent;
COMMTIMEOUTS CommTimeOuts;

printf(" Inside CommThreadProc \n" );
//Opening the COM port
hCommPort = CreateFile( "COM1",
GENERIC_READ,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0 );

if( hCommPort == INVALID_HANDLE_VALUE )
{
printf( "Error while Opening COM Port \n" );
return 0;
}
//Getting COMM settings
GetCommState( hCommPort, &dcb );

dcb.BaudRate = CBR_9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;

SetCommState( hCommPort, &dcb );


//Creating overlapped event handle
comReader.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );


SetCommMask( hCommPort, EV_RXCHAR );

BOOL repeat = true;

while( 1 )
{
WaitCommEvent( hCommPort, &dwCommEvent, &comReader );
if( WaitForSingleObject( comReader.hEvent, INFINITE ) == WAIT_OBJECT_0 )
{

do
{
Success = ReadFile( hCommPort, lpBuf, 512, &dwRead, &comReader );

if( !Success )
if (GetLastError() == ERROR_IO_PENDING) // read not delayed?
printf( "Error in reading the file \n");
else
{ // writing the data into a file
FilePtr = fopen( gszFilePath, "a" );

if( FilePtr != NULL )
{
fwrite( &lpBuf, dwRead, 512, FilePtr );
}
else
printf( "Error while opening file" );

fclose( FilePtr );
}
}while( dwRead > 0 );

}
}

CloseHandle( comReader.hEvent );
CloseHandle( hCommPort );


return 1;
}
 
change:
hCommPort = CreateFile( "COM1",
GENERIC_READ,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0 );

to:
hCommPort = CreateFile( "COM1:",
GENERIC_READ,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0 );

you need a ":" (colon) after COM1. and you don't need two quotes after COM1.
 
eh.. sorry.. you didn't have two quotes.. i mis typed the colon as a quote and thought you did! just realized what happened.. but you do need the colon
 
Drewdaman, thank you for answering.... I tried using a colon after the COM1, but it still getting the same error :(.
 
hmm.. you do definitely need the colon.. so don't remove that! i'm working on something similar..

i have a feeling that your com port is nto being opened correctly. try using:
Code:
hCommPort =CreateFile("COM1:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);

Does the line "Error while Opening COM Port \n" print?

 
Thanks Drewdaman. Nope it is not printing. I checked the handle after opening the COM port and I am getting a valid handle.

if( hCommPort == INVALID_HANDLE_VALUE ) So I am thinking that it is opening the COM port correctly..

Do I need to change any values in the OVERLAPPED structure?
 
hmm.. i dont' know what to tell you then! :(

i would suggest you comment all your code after connecting adn see if you can read a single byte from the port. if that works, then your error is not in the ReadFile thing.. it is somewhere else.

what is the device that you have connected to the com port?
 
Actually the program is to read data from a DATA SWITCH but now it is connected to serial port of another system and I am using the MS Allen Denver's 4918 program to write the data to serial port.

I will try to comment the rest of my code and see..
 
Hey drewdaman... I got that error fixed... I changed the
buffer declaration

char * lpBuf = ""; to
char lpBuf[ 512 ] = "";

and it worked. Below is the article that helped me
Now I am getting a new Error... ERROR_IO_PENDING -- 997

Did you ever get that error before?
 
Do you actually have a device writing to your serial port?
How are you sending data to your port?
 
i have got that before.. in fact, i count on it in my code!
take a look at this link:


this is a code snippet from there, but take a look at the link.. you might find it useful.. there is a lot of good info there!

Code:
BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)
{
   OVERLAPPED osWrite = {0};
   DWORD dwWritten;
   DWORD dwRes;
   BOOL fRes;

   // Create this write operation's OVERLAPPED structure's hEvent.
   osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
   if (osWrite.hEvent == NULL)
      // error creating overlapped event handle
      return FALSE;

   // Issue write.
   if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {
      if (GetLastError() != ERROR_IO_PENDING) { 
         // WriteFile failed, but isn't delayed. Report error and abort.
         fRes = FALSE;
      }
      else
         // Write is pending.
         dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
         switch(dwRes)
         {
            // OVERLAPPED structure's event has been signaled. 
            case WAIT_OBJECT_0:
                 if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, FALSE))
                       fRes = FALSE;
                 else
                  // Write operation completed successfully.
                  fRes = TRUE;
                 break;
            
            default:
                 // An error has occurred in WaitForSingleObject.
                 // This usually indicates a problem with the
                // OVERLAPPED structure's event handle.
                 fRes = FALSE;
                 break;
         }
      }
   }
   else
      // WriteFile completed immediately.
      fRes = TRUE;

   CloseHandle(osWrite.hEvent);
   return fRes;
}
 
Hi Wings, I am writting the data to the COM port from another machine using MS Allen Denver's program 4912. I got that error fixed.... I declared the buffer size as 512 before so the Read is waiting till the buffer is full in the mean time it is issuing error 997, so I am reading character by character and it is working now......
 
hello,
cplsplsprogrammer i have a question for you! i saw on many sites that they read from the serial port one byte at a time. is there any advantage to doing it this way rather than reading a bunch of bytes at a time?
 
Hey Drewdamn, there is not particular advantage reading byte by byte but if you know the data size arriving at the COM port and if it same size all the time you can read more than one byte but if you dunno the size and if you have your buffer lenght more than the data arrived it will give you error 997 (ERROR_IO_PENDING) till it gets all the data into the buffer. So the best option is to read the minimum number of bytes if you know the lenght if not byte by byte.
 
oh ok.. cool.. so in my case, there is no advantage.. that is good news because i dont have to change my code! thanks!
 
Your code has 1 big bug - you are opening the file for overlapped I/O, but you're not actually HANDLING overlapped I/O. For example, you are treating ERROR_IO_PENDING as a failure, but it is not. It is a normal result of overlapped I/O when there is insufficient data to satisfy your request or if, for other reasons, Windows isn't going to deal with you right then. If ERROR_IO_PENDING is not returned, then your I/O is DONE. If it DOES, then you need to wait for the pending I/O to complete. (If you're not handling ERROR_IO_PENDING already, then you need to re-read the Windows serial I/O documentation and particularly the parts about overlapped I/O). Of course, if the example you have is actually what you're wanting to do, i.e., read all available data in a loop in an asynchronous thread, then you don't need to be using overlapped I/O - just set the comm timeouts correctly and read in a loop basically as you are now.

But - hang as big a read as you are prepared to handle, and let the device driver give you all the data it can at one time. If your port timeouts are correct, this will cause the precise behavior that you are expecting - you'll get all available data (up to the requested read length) once there are any bytes available to deliver to you.

And, finally, the people that you see doing single-character I/O don't understand how to set the comm port timeouts, usually. Set the timeouts so that it returns only when one or more bytes of data are available to be read. you will then get chunks of data in various sizes back from your reads.

(of course, you'll also want to put that I/O buffer size (512) in a const and allocate the buffer dynamically too when you get around to it, right? <G>)

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top