Re: rs232 -help!
 
Hello Heinz,
Okay, I never really found out how to set the comm timeout, however I got it 
to work with the following code. I can read the port and the Read functon 
will fill the buffer and return. I will then store it in a back-up-buffer 
which will hold the expected data. Next I increment a variable so to never 
come back to the back-up-buffer while Read returns any subsequent junk (It 
returns junk for one or two iterations), so I just ignore this. When finished 
reading junk, it breaks out of the loop, and the next message will obviously 
not be related to an rs232 event and so, we reset the counter value, hence 
the Read function will now be ready for the next rs232 event.
See the code below: 
============================================
//Global object declared one time
CSerialWnd MySerial;
LRESULT CALLBACK WndProc_CW1 (HWND hwnd, UINT message,
                      WPARAM wParam, LPARAM lParam) 
{
static DWORD dwBytesRead = 0;
static BYTE  abBuffer[8];
static TCHAR szBuffer[17];
static int  LoopCount = 0;	   
//Serial port monitor
if (message == CSerialWnd::mg_nDefaultComMsg)
{
// A serial message occurred
const CSerialWnd::EEvent eEvent = CSerialWnd::EEvent(LOWORD(wParam));
const CSerialWnd::EError eError = CSerialWnd::EError(HIWORD(wParam));
MySerial.Setup(CSerial::EBaud9600,CSerial::EData8,
    CSerial::EParNone,CSerial::EStop1);	
  switch (eEvent)
  {
   case CSerialWnd::EEventRecv:
         do
          {
 	MySerial.Read(abBuffer,sizeof(abBuffer),&dwBytesRead);
    if (LoopCount == 0){
         MultiByteToWideChar(CP_ACP,0,
        (LPCSTR)abBuffer,8,szBuffer,17);  //Store in back up buffer
           LoopCount ++;}
    else
          {/*Do nothing*/}
           }while(dwBytesRead == sizeof(abBuffer));
           break;
           default:
    break;
       }
return 0;
}
else
LoopCount = 0;
....other code.....
switch(message)
{
case WM_CREATE:
MySerial.Open(TEXT("COM1"),hwnd,WM_NULL,lParam,0,0);
....other code....
case WM_CLOSE:
MySerial.Close();   	
.... other code ...
}	
=====================================================
It never hangs anymore, and the data gets read in one whole string and any 
size aswell.  Actually I haven't tested how many successive bytes I can read 
at once, but I know that I have done many tests, and I can read one to 8 
bytes no problem, I will try to increase the for loop in the controller so to 
send 100 bytes, I don't think it will a problem!
Anyhow, this has been a tough one, and I thank all the fellows who 
contributed to my rs232 dilema. I don't know if I will run into problems with 
the code above, however I tell ya, this is the best I can get so far and I 
figure I should share it with you. Its the least I can do. I don't say that 
ist the best way of doing this, however, it works!
I will try to look for more documentation so I can get familliar with the 
whole library  options. I don't know if there is other ways of reading an 
rs232 port asides from using the SerialWnd class.... I see people using Read 
and write functions????? Anyhow for now this will do
But I will be honest with you Heinz, in spite of all the help I have gotten, 
at a certain point, I was reading over and over all the *much appreciated* 
posts from everyone, and then I read over the rs232 documentation, and then I 
re-read your post.... and your last paragraph is what gave it away:
"Read the documentation of CSerial what EReadTimeoutBlocking really means. 
The name suggests that the read hangs until the requested number of bytes is 
available. Such behaviour does not really work well with (Windows-) message 
driven applications. When you read whenever data is signaled to your 
application, you should use small timeouts and never read more bytes then 
available at that time."
This paragraph somehow lead me back to the documentation and thats where I 
read about the following snippet of code in the document.
==================================================
DWORD dwBytesRead = 0;
BYTE  abBuffer[100];
do
{
// Read data from the COM-port
serial.Read(abBuffer,sizeof(abBuffer),&dwBytesRead);
if (dwBytesRead > 0)
{
// TODO: Process the data
}
}
while (dwBytesRead == sizeof(abBuffer));
==============================================
I   !!!!only!!!!    read the document 3 times (How slow can I be!), And the 
explanation stipulates:
"Make sure you always read the entire buffer after receiving the EEventRecv 
event to avoid you lose data."
And so I adapted it to what I did and merging the combined efforts of all 
the posts,  I got something that is functional. 
In short, for now, I will use what works!
Thankyou very much Heinz, John, Scott and Frank ! All posts are much 
appreciated!
-- 
Best regards
Robert
"Heinz Ozwirk" wrote:
"Robby" <Robby@discussions.microsoft.com> schrieb im Newsbeitrag 
news:91E88AF3-C15C-4E6E-9D57-C5E79F7F688D@microsoft.com...
Hello,
At this point if anyone has used the CSerialWnd class from code project, I
am desperately in need of a code sample doing a Read task from rs232.
I have been exploiting this subject with some of the most credible fellows
on this newsgroups and I fully appreciated their support and wish to
continue. I am re-starting this subject so not to clutter the previous 
post
and to give the full story in case I didn't post it right before.
Right now I have the following code:
===========================================
//Global object declared one time
CSerialWnd MySerial;
LRESULT CALLBACK WndProc_CW1 (HWND hwnd, UINT message,
              WPARAM wParam, LPARAM lParam)
{
static DWORD dwBytesRead = 23;
static BYTE  abBuffer[23];
static TCHAR szBuffer[49];
MySerial.Open(TEXT("COM1"),hwnd,WM_NULL,lParam,0,0);
//Serial port monitor
if (message == CSerialWnd::mg_nDefaultComMsg)
   {
    // A serial message occurred
  const CSerialWnd::EEvent eEvent = CSerialWnd::EEvent(LOWORD(wParam));
  const CSerialWnd::EError eError = CSerialWnd::EError(HIWORD(wParam));
  MySerial.Setup(CSerial::EBaud9600,CSerial::EData8,
        CSerial::EParNone,CSerial::EStop1);
  MySerial.SetupReadTimeouts(CSerial::EReadTimeoutBlocking);
 switch (eEvent)
{
    case CSerialWnd::EEventRecv:
    MySerial.Read(abBuffer,sizeof(abBuffer),&dwBytesRead);
    //abBuffer[dwBytesRead] = 0;  //Null character is now included in
receiving msg
         break;
    default:
         break;
}
MultiByteToWideChar(CP_ACP,0, (LPCSTR)abBuffer,23,szBuffer,49);
MySerial.Close();
return 0;
}
I don't know the details of your CSerialWnd class, so I can only add some 
general comments.
1. Usually you should not open the port, initialize it and close it again in 
each and every message sent to a window. Usually you should open and 
initialize the port once when your program starts and close it only when 
your program terminates (or you don't want to receive more data).
2. Often serial ports don't give you the number of bytes you are asking for. 
You'll get as many bytes as are available when the read function is called. 
You have to test the number of bytes returned, and if not enough data is 
available yet, you have to store what you have got and wait for more data to 
be sent.
3. Often serial ports signal each byte they are receiving, or or groups of 
bytes when there is some delay between them. But the receiver might read all 
bytes when it processes the first event. Then more events may be in the 
window's message queue, but the bytes causing them have already been read. 
This especially happens when you slow down your receiver while debugging. 
For the first byte a message is sent to your window. This message is 
processed and execution stops at the breakpoint before calling Read. While 
the debugger waits for you to step through your code, mode data might arrive 
and Read will return those bytes, too. But messages generated for those 
bytes are still in the queue and will be processed once you have stepped 
through your code. Now when the next message is processed, the data causing 
that message have already been read, and Read will wait for the specified 
time. Try to find out how to determine the number of bytes available and 
only read that many bytes.
4. Don't use too large timeouts. The read intervall timeout depends on the 
behaviour of the sender of your data. How long does it need between sending 
two bytes. This timeout should be large enough for the sender to fetch and 
transmit the next byte. But values about 100ms should be large enough. The 
timeout multiplier depends on the selected baud rate. The higher that rate, 
the smaller this value can be. With 9600 baud you can transmit a little less 
than 1000 characters per second, so this timeout could be 2ms, but larger 
values usualy will not be harmfull. The total constant timeout basically 
determines the time a blocking read waits when no data is available. Usually 
I use values between 0.5 and 5 seconds.
But whatever timeouts you are using, be prepared that you do not read as 
many bytes as you are expecting. Provide some way to collect data of 
multiple reads and process them only when you got all the data you need.
The correct message was returned. However, immediately after, VC++ shows 
my
program going back again to the break point a second time without me 
having
sent another message to the port. I guess this event is caused by some 
junk
left over in the serial buffer. So I step to the Read statement.... and 
then
VC++ hangs thereafter!
First, I don't know if my Comm timeout is well set.... ? Obviously, if it
were, well then the Read function would of returned.... right?
Read the documentation of CSerial what EReadTimeoutBlocking really means. 
The name suggests that the read hangs until the requested number of bytes is 
available. Such behaviour does not really work well with (Windows-) message 
driven applications. When you read whenever data is signaled to your 
application, you should use small timeouts and never read more bytes then 
available at that time.
HTH
    heinz