From: jcp@werple03.mira.net.au (John Peterson)
Subject: [delphi] Problems with tips&tricks COMM component
Date: Sat, 29 Jul 1995 16:24:02 +1000

Firstly, I have only been subscribing to this group for 2 days and 
immediately found help on the major problem I am having in moving from BC++ 
-> delphi, namely handling of Data Comms....Thanks for the help.

I've been working with the COMM component and found the following problems 
which could cause lockups on incoming Data.

1. Occasionally we will get a both a CN_RECEIVE and CN_EVENT in one message, 
giving an lParamLo value of 5. TComm.WndProc is written to handle only one 
Event at a time. The following solves this problem:

-----------------------------------------------------
procedure TComm.WndProc(var Msg:TMessage);      
begin
  with Msg do
  begin
    if Msg=WM_COMMNOTIFY then
    begin
      if lParamLo AND CN_EVENT <> 0 then DoEvent;
      if lParamLo AND CN_RECEIVE <> 0 then DoReceive;
      if lParamLo AND CN_TRANSMIT <> 0 then DoTransmit;
    end
    else
      Result:=DefWindowProc(FWindowHandle,Msg,wParam,lParam);
  end;
end;
---------------------------------------------------------------

2. When processing the CN_RECEIVE message, you must read enough characters 
to get below "RxFull" characters left in the receive queue. If this does not 
happen, we will never see another WM_COMMNOTIFY, CN_RECEIVE.
The way I solve this problem is to check if the queue has less than RxFull 
characters in it, and if not post another WM_COMMNOTIFY message to repeat 
the read. See below...

---------------------------------------------------------------
procedure TComm.Read(Data:PChar;Len:Word);
var
  Stat : TComStat;
begin
  if hComm<0 then exit;
  if ReadComm(hComm,Data,Len)<0 then Error:=True;
  GetCommEventMask(hComm,Integer($FFFF));

  { if we haven't read below FRxFull, reshedule another COMMNOTIFY to read
        again....this will repeat until we are below
  }
  GetCommError(hComm, Stat);
  if Stat.cbInQue > FRxFull then
    PostMessage(FWindowHandle, WM_COMMNOTIFY, hComm, CN_RECEIVE);
end;
---------------------------------------------------------------

3. EV_RXCHAR - Is is possible to get into a state where we get an EV_RXCHAR 
event when there is more than 1 character in the queue, this has the effect 
of making the receive queue look like a FIFO. The best way to handle this 
depends on the application. I my apps (comms protocol handlers), the RXCHAR 
handle must be prepared to read more than one character.

Having come from a Borland C++ and OWL background (groan) ;-), Delphi sure 
makes the UI easy, however it appears that there is excessive overhead in 
the decoding the CN_EVENT into a set, then decoding it in the user defined 
handler.  Any comments/experiences on the performance hit Delphi's handlers 
cause, especially in hgigh speed data apps.

regards
John Peterson
jcp@werple.mira.net.au

------------------------------------------------------------------------------

From: pak00465@pixie.co.za (Carl Mes)
Subject: Problems with COMM component on Tricks & Tips Page ...
Date: Fri, 28 Jul 1995 10:42:14 +0200

Hello, here's a duplicate of mail I left on Delphi-Talk, regarding the Comm
component on the Tricks & Tips WWW page.

>> As a thought - have you seen the generic Delphi comm component on the
>
>I tried the tComm from the Tips & Tricks page.  I could not get it to 
>work at 14.4 as it seemed to hang when receiving a lot of text.  I added 
>flow control, but that did not fix my problem.  I suggest you send your 
>improvement to the Tip & Tricks site.
>
>Andy

The code will hang at high speed, because it is event driven. When the comm
driver sends an interrupt (See SetCommEventMask in Win/API), it triggers the
component, which in turn runs the code in your event. The problem is that is
your event has not finished processing, Delphi will run two events on top of
each other. You can verify this by putting a ShowMessage('Rhubarb') in the
event. If you send a couple of characters at the comm port, a couple of
'Rhubarbs' will pop up on your screen.

The example event code actually processes the incomming characters right
there and then. This poses a problem: for example :
- I send 50 characters at the comm-port.
- After 25 characters the event triggers, with BufferSize as 25. It then
begins   to read the characters out of the buffer.
- Characters are still comming in, and after 50 bytes, the event triggers again.
  The first event however, has only read 10 bytes out of the buffer, so the
BufferSize will be 40.

Problem! Event1=25 and Event2=40 mean that my code is trying to read 65
bytes, when there are only 50... Oops! This problem is obviously dependant
on machine speed, as well as modem speed. If you only use 2400 on a Pentium,
there is ample time to process incomming characters, and Event1 will finish
before Event2.

Here's what I did to solve the problem:
- I created a timer event, which checks for characters every 100ms.
- In the timer event:
   - Check if any chars in buffer, return if none. (See functions below)
   - Disable the timer !!!! (Otherwise the same problem occurs)
   - Process characters....
   - Re-Enable the timer.

The following two functions I added in the comm component, for getting the
size of the appropriate buffer:

function TComm.GetRxSize:Word;
var
  Stat:TComStat;
begin
  result := 0;
  if (hComm < 0) then Exit;
  GetCommError(hComm, Stat);
  result := Stat.cbInQue;
end;

function TComm.GetTxSize:Word;
var
  Stat:TComStat;
begin
  result := 0;
  if (hComm < 0) then Exit;
  GetCommError(hComm, Stat);
  result := Stat.cbOutQue;
end;


I hope this information is of some use, (Sorry if I was a bit verbose :)

Cheers, CARL (pak00465@pixie.co.za)


