Mega Code Archive

 
Categories / Delphi / Examples
 

Comm2

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)