S
Slobodan Brcin \(eMVP\)
As mentioned in the previous reply post, if 2nd parameter of ReadFile is set
I do not understand :-(
Second parameter is lpvBuf, right? Why would you like to set it to 0?
I need to see piece of code that you wrote starting from read_os, write_os structure initialization. And that include both readfile
and writefile operations, without any line skipped in between.
Use null cable and second computer to receive text. Then try using WriteFile few times one after another to send some different
data. Look if you will receive in terminal all bytes that you have send. (You will probably have data loss since you did not waited
for transmit to be over, but this is the issue that you have probably not seen yet)
Regards,
Slobodan
NULL, GetLastError doesn't return ERROR_IO_PENDING.
I do not understand :-(
Second parameter is lpvBuf, right? Why would you like to set it to 0?
I need to see piece of code that you wrote starting from read_os, write_os structure initialization. And that include both readfile
and writefile operations, without any line skipped in between.
I used some free tools that monitor serial port I/O. I could confirm the
output data flow but not input data at all.
Use null cable and second computer to receive text. Then try using WriteFile few times one after another to send some different
data. Look if you will receive in terminal all bytes that you have send. (You will probably have data loss since you did not waited
for transmit to be over, but this is the issue that you have probably not seen yet)
Regards,
Slobodan
George said:As mentioned in the previous reply post, if 2nd parameter of ReadFile is set
NULL, GetLastError doesn't return ERROR_IO_PENDING.
I modified the code thus,
ReadFile(hComm, lpvBuf, cbRead, &dwBytesRead, &read_os);
GetOverlappedResult(nComID, &read_os, &dwBytesRead, TRUE);
This code worked well. But the problem is that overlapped operation does not
terminate both WaitCommEvent and ReadFile.
I used some free tools that monitor serial port I/O. I could confirm the
output data flow but not input data at all.
Does this mean that OS input queue does not receive any data from commport?
Slobodan Brcin (eMVP) said:George,
And my 0.02$ to this:
rc = ReadFile(hComm, lpvBuf, cbRead, &dwBytesRead, &read_os);
if (!rc && (GetLastError() == ERROR_IO_PENDING)) {
if (WaitForSingleObject(read_os.hEvent, 1000)) {
dwBytesRead = 0;
} else {
rc = GetOverlappedResult(nComID, &read_os, &dwBytesRead, FALSE);
if (rc) {
read_os.Offset = dwBytesRead;
}
}
} else {
read_os.Offset = dwBytesRead;
}
There is no offset value on pipes and serial drivers. (What would offset mean in a continuous stream without beginning and the end
to the driver)
To reduce confusion to yourself instead of:
rc = ReadFile(hComm, lpvBuf, cbRead, &dwBytesRead, &read_os);
Use:
rc = ReadFile(hComm, lpvBuf, cbRead, 0, &read_os);
dwBytesRead in overlapped case has no meaning.
WaitForSingleObject do not use this, especially not in test sample.
Also use GetOverlappedResult with TRUE.
For instance following should work instead of your code above:
ReadFile(hComm, lpvBuf, cbRead, 0, &read_os);
GetOverlappedResult(nComID, &read_os, &dwBytesRead, TRUE);
Regards,
Slobodan
driverKM said:George,
Not going deeply in to the code, a couple of glitches:
- If you open file with FILE_FLAG_OVERLAPPED, you must set the last parameter of the WaitCommEvent to not NULL and pass a
manual-reset event object.
You have, however, this: WaitCommEvent(nComID, &dwEvtMask, NULL);
Please see the msdn sample the link to I posted in some previous reply in this thread.
- For debugging purposes make your code single threading. That may be easy if instead of CreateThread(..., CommPortMonitor,...)
you just call CommPortMonitor.
KM
This is the part of my application that regards to commport communication.
Wait CommEvent thread loop terminates only when application terminated or
fContinue flag turned into ON.
WriteFile() goes well without any problem and the device connected works as
designed.
The device returns correct data for the command sent from my application.
But WaitCommEvent() never returns though the data sent from the device
correctly arrive at the comport.
/***********************************************************************************************
*******************************************Open
ComPort*****************************************
************************************************************************************************/
long OpenCommPort(){
DCB dcb;
HANDLE nComID;
COMSTAT ComStat;
BOOL bBuildComm;
BOOL bSetCommStateRtn;
char szPortSet[256];
//////////////////////// CreateFile
/////////////////////////////////////////////////
nComID = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
//////////////////////// BuildComm
/////////////////////////////////////////////////
dcb.DCBlength = sizeof(DCB);
GetCommState(nComID, &dcb);
strcpy(szPortSet, "COM1:9600,e,7,2");
bBuildComm = BuildCommDCB(szPortSet,&dcb);
/////////////////////// SetCommState
/////////////////////////////////////////////
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
dcb.wReserved = 0;
dcb.BaudRate = CBR_9600;
dcb.fParity = TRUE;
dcb.Parity = 2;
dcb.ByteSize = 7;
dcb.StopBits = 2;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fDsrSensitivity = FALSE;
//XON/XOFF
dcb.fOutX = TRUE;
dcb.fInX = TRUE;
dcb.fTXContinueOnXoff = TRUE;
dcb.XonLim = 2048;
dcb.XoffLim = 2048;
dcb.XonChar = 0x11;
dcb.XoffChar = 0x13;
dcb.fBinary = TRUE;
dcb.fNull = FALSE;
dcb.fAbortOnError = TRUE;
dcb.fErrorChar = FALSE;
dcb.ErrorChar = 0x00;
bSetCommStateRtn = SetCommState(nComID, &dcb);
/////////////////////////////////////////////////////////////////////////////////////////////
if (PurgeComm(nComID, PURGE_TXCLEAR | PURGE_RXCLEAR) != TRUE) {
if (GetLastError() != CE_MODE) {
DWORD dwErrors;
if (ClearCommError(nComID, &dwErrors, &ComStat) != TRUE) {
return GetLastError();
}
}
}
COMMTIMEOUTS comm_timeout;
comm_timeout.ReadIntervalTimeout = MAXDWORD;
comm_timeout.ReadTotalTimeoutMultiplier = 0;
comm_timeout.ReadTotalTimeoutConstant = 0;
comm_timeout.WriteTotalTimeoutMultiplier = 0;
comm_timeout.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(nComID, &comm_timeout)) {
return -1;
}
if (ThreadHdl == NULL) {
ThreadHdl = CreateThread(NULL, 0, CommPortMonitor,
this, CREATE_SUSPENDED, &ThreadID);
if (ThreadHdl == NULL) {
return -1;
}
ResumeThread(ThreadHdl);
}
return 0;
}
/***********************************************************************************************
***********************************Wait CommEvent
Thread*****************************************
************************************************************************************************/
extern "C"
DWORD __stdcall CommPortMonitor( void* pparam )
{
DWORD dwEvtMask; // kind of communication event(set in
WaitCommEvent())
DWORD dwError;
COMSTAT ComStat; // status of communication port(set in
ClearCommClear())
BOOL bRet;
int nReadCnt; // bytes received(return value of ReadComPort())
bSetMask = SetCommMask(nComID, EV_RXCHAR | EV_ERR);
while (TRUE) {
bRet = WaitCommEvent(nComID, &dwEvtMask, NULL);
if (!fContinue) {
break;
}
ClearCommError(nComID, &dwError, &ComStat);
if (!bRet) {
PurgeComm(nComID, PURGE_TXABORT | PURGE_RXABORT);
continue;
}
}
if (dwEvtMask & EV_ERR) { // CE_FRAME, CE_OVERRUN, CE_RXPARITY
//error-handling
continue;
}
if (ComStat.cbInQue > 0) { // check existence of receive data
ReadComPort(nComID, byBuffer, 1024);
//data-handling
}
}
return TRUE;
}
/***********************************************************************************************
*****************************************Read
Data***********************************************
************************************************************************************************/
int HWPIN::ReadComPort(HANDLE hComm, void* lpvBuf, int cbRead)
{
DWORD dwError;
COMSTAT comstat;
BOOL bContinue = TRUE;
DWORD dwBytesRead = 0;
BOOL rc = 0;
read_os.Offset = 0;
rc = ReadFile(hComm, lpvBuf, cbRead, &dwBytesRead, &read_os);
if (!rc && (GetLastError() == ERROR_IO_PENDING)) {
if (WaitForSingleObject(read_os.hEvent, 1000)) {
dwBytesRead = 0;
} else {
rc = GetOverlappedResult(nComID, &read_os, &dwBytesRead, FALSE);
if (rc) {
read_os.Offset = dwBytesRead;
}
}
} else {
read_os.Offset = dwBytesRead;
}
if (rc) {
return read_os.Offset;
} else {
// error handling
PurgeComm(nComID, PURGE_TXABORT | PURGE_RXABORT);
ClearCommError(nComID, &dwError, &comstat);
return -1;
}
}
/***********************************************************************************************
****************************************Write
Data**********************************************
************************************************************************************************/
int HWPIN::WriteComPort(HANDLE hComm, const void* lpvBuf, int cbWrite)
{
DWORD dwError;
COMSTAT comstat;
DWORD dwBytesWritten = 0;
BOOL rc = 0;
write_os.Offset = 0;
rc = WriteFile(hComm, lpvBuf, cbWrite, &dwBytesWritten, &write_os);
if (!rc && (GetLastError() == ERROR_IO_PENDING)) {
if (WaitForSingleObject(write_os.hEvent, 1000)) {
dwBytesWritten = 0 ;
} else {
rc = GetOverlappedResult( nComID,
&write_os,
&dwBytesWritten, FALSE);
if (rc) {
write_os.Offset = dwBytesWritten;
}
}
} else {
write_os.Offset = dwBytesWritten;
}
if (rc) {
return write_os.Offset;
} else {
// error handling
PurgeComm(nComID, PURGE_TXABORT | PURGE_RXABORT);
ClearCommError(nComID, &dwError, &comstat);
return -1;
}
}
:
Hi George,
No matter what SetumComm settings that you use (default) serial driver should work.
You have a logic error in your code regarding when you expect to get some data.
Post here complete segment starting with readfile and explain what do you expect to get with each next API call. (This is few
lines
that you should try to explain to your-self, but doing that "aloud" ca usually help)
Regards,
Slobodan
I tested with a simple application in a simple condition.
Connect 2 PCs with serial cable and run above application on both PC.
Everything went well all around.
The data packet sent from 1 PC could be correctly received by another PC.
If some character data is reached to the system receive buffer,
WaitCommEvent is terminated and ReadFile correctly read buffer data.
According to this result, I think the receive data logic is not wrong.
Some field of DCB structure, 2nd parameter of SetCommState, may be wrong for
my appllication or device (or XP Embedded component configuration).
By the way, I found the API SetupComm. Is this API necessary for our
application?
:
George,
Somehow I seem to overlook your reply in this thread.
HasOverlappedIoCompleted returns FALSE.
Yup. This is what we expected, right?
It would be worse if it returned TRUE while GetOverlappedResult returned 0 bytes transferred.
By the way, just after SetCommMask() returns TRUE, GetCommMask() returns
FALSE. Why?
How about checking with GetLastError?
Any 2nd parameter of SetCommMask() results in the same.
Please look at this MSDN sample code to see how it should work in a simple case:
http://msdn.microsoft.com/library/en-us/devio/base/monitoring_communications_events.asp
Your problem does not seem to be related to XPe. You would better off developing, texting and debugging the app on XP Pro
first
and
then move to XPe.
As Slobodan mentioned you can get more help if you open more sources and post in more appropriate NG.
Regards,
KM
:
Just to add to that..
George, look at the HasOverlappedIoCompleted macro to see if it can help to determine the completion of an outstanding
I/O
operation.
--
Regards,
KM, BSquare Corp.
Hi George,
One basic question do you know how overlapped operation are working?
You should choose between one of two following syntaxes.
ReadFile(ComID, lpvBuf, nRead, 0, &read); -----> For overlapped access
ReadFile(ComID, lpvBuf, nRead, &BytesRead, 0); ---> For regular access.
Using both values with overlapped access does not make sense since all operations will return immediately and set
BytesRead to
0
or
some unknown value that represent some data that was already available in internal OS buffers, depending on
thatnoyou
use.
But
this length info is usually 0 (treat is as undefined).
Length info is filled only during the IO API call not later.
So only way for you to obtain current results of overlapped operation is to read overlapped structure directly or use
API
functions
like GetOverlappedResult.
Also all operations on buffer are not synchronous but rather asynchronous. This mean that you can issue few different
read
and
write
operations on different handles and still execute some other code while drivers and hardware gather your data.
Regards,
Slobodan
Depend on queue status? What's that?
Yes, I tried to GetOverlappedResult() with 3rd parameter TRUE, but no
difference.
GetOverlappedResult() returns successfully but "BytesRead" is always 0.
:
Hi George,
I have not tested another OS than Windows XP Embedded.
Does OS matter about this phenomenon?
Not really, but this NG is less apropriate for this type (API programmming type) of questions. And one SDK/DDK
related
would
be
better for obtaining answers on these topics. When you have something tha twork on XP Pro and do not work on XPe
then
this
is
NG
to
ask for help.
OK I'll try to make test program without sub-thread and set timeout properly.
R/W file operation is simple as below. This operation is done after (10)'s
check.
ReadFile(ComID, lpvBuf, nRead, &BytesRead, &read);
WriteFile(ComID, lpvBuf, nWrite, &BytesWritten, &write);
With overlapped structured BytesRead, BytesWritten usually do not contain values that you expect and they will be
most
likely
0
(depending on queue status).
Wait for completion of overlapped operaion.
GetOverlappedResult(ComID, &write, &BytesWritten, FALSE);
Since both read and write are overlapped, please use GetOverlappedResults to wait for operation to complete after
both
read
and
write operations. Ase last parameter as TRUE for test cases.
Check if "BytesWritten" is over zero, and application specific process.
I also tried without using WaitCommEvent but only ReadFile within eternal
while loop, but the result was same. No data could be read.
What is wrong?
Probably you do not wait to receive data with GetOverlappedResult. (Without complete code I can't tell for sure).
BIOS level setting?
NO. Has nothing to do with this.
OS setting?
NO, since you configure DCB, timeouts etc.
Shortage of pre-configuration in my application?
NO. You have configured all that is needed. But set timeouts (if you want them, for test they are not important)
Regards,
Slobodan
:
Hi George,
Does this work on XP Pro?
Why do you create new thread for simple test? Simplify your test case.
Always use timeouts for receive operation. (Unless you want your program to stuck if there is not enough data
requested by
read
operation).
Either SetCommMask or WaitCommEvent caused problems for me long time ago so I do not use them.(There is
needfor
them
especially
since you use overlapped access).
Where are read and write file in your example?
Regards,
Slobodan
Hi.
Please give me some advise.
I want to communicate with a device via COM port and coded typical
communication program using Windows SDK.
The program sequence is thus...
(1) CreateFile with overlap mode.
ComID = CreateFile("COM1",GENERIC_READ | GENERIC_WRITE, 0,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
(2) BuildCommDCB
BuildCommDCB("COM1",&dcb);
(3) SetCommState with some parameter set by the value the device requires
and others by default.
SetCommState(ComID, &dcb);
(4) SetCommTimeouts with no timeout.
SetCommTimeouts(ComID, &comm_timeout);
(5) SetCommMask
SetCommMask(ComID, EV_RXCHAR);
(6) CreateThread.
(7) In the thread created above, WaitCommEvent for a data sent from the
device.
WaitCommEvent(ComID, &EventMask, &event);
(8) Wait until the overlapped operation complete.
GetOverlappedResult(ComID, &event, &Transfer, TRUE);
(9) Get error code and clear.
ClearCommError(ComID, &Error, &ComStat);
(10) Check the receive queue if some data is received.
The problem is that function WaitCommEvent never return!
Instead of WaitCommEvent, I tried to ReadFile(COM1) directly in while loop,
but the loop never ended.
I confirmed that the command from application to the device is correctly sent.
And also confirmed by line monitor connected between the device and COM port
that the device returns correct response for the command sent by my
application.
But why my application can't receive any data?
Almost all the settings are set by general value.
OS is Windows XP Embedded with almost full functionality configuration.
Please help me. Thanks.