I'm having an odd problem, when under heavy load we get spurious extra data in the receive queue. The application isn't doing anything odd, simply using a TApdComport (no events, 9600-8-N-1 no flow control). We call read the data via calls to GetChar (I recently peppered the code with .ProcessCommications calls, with no effect).
In the example cases we have, the received data is roughly 35 bytes in length. I have confirmed that the extra byte is not 'on the wire' via a hardware serial monitoring device that logs all tx/rx data.
I do not have this problem is I use a different serial component, but alas APD is much less CPU intensive..
Oh, and I'm using the latest release version.. just downloaded this morning.
Delphi, under WinXP.
Anybody else ever see this?
I have never heard of anyone else having this problem. However, repeated calls to GetChar is not the way to read data from TApdComport. You should define a DataAvail trigger and wait for data to arrive at the event handler. Apro is not designed to work well in an application that loops waiting for data to arrive from the port. You should always use events to receive your data and allow your program to yield control until the event fires.
That would be fine and dandy, if we could. This is a legacy product, originally written in DOS that's been ported to Windoze (wasn't my idea, but I couldn't get them to let me port it to *nix ;-).
It's fairly large and complex and runs as a service, or in test mode as a console application.
As far as yeilding control, the application uses on average under 2% CPU.. so it's not a case of hogging resources or processor time. Calls to GetChar should remove the character from the receive queue, but that appears to not be always the case.
If you are porting a DOS application then you would probably be better off just reading and writing the serial port directly using ReadFile and WriteFile. Serial port I/O under Windows isn't all that difficult and for simple apps that just read and write the serial port using a component like Apro is a bit like using a sledge hammer to drive a carpet tack. I use Apro myself, but for simple serial I/O I don't bother with it, I just go straight to the serial port.
APD is way less CPU intensive in the current system, in particular servicing multiple comports. At least with the various other lightweight, direct to WinAPI (readfile,writefile) methods I've tried so far.
One should be able to call GetChar without fear of bogus data.
That being said, I may have an idea. I was checking for InBuffUsed > 0 to determine if a character is ready, that's probably not the right way to do it. Changed to a test on CharReady, hopefully that will help.
Without truly knowing the depth of your application, I also agree that triggers is the way to go. Even if the cpu usage is low, polling the serial port is still cpu intensive. Years ago, I had issues with extra chars but eliminated the problem by using triggers.
To use triggers within a console application or within an NT service, you need to build a message pump. This will allow the components to work without using a Delphi form.
Very simple message pump:
// Run simple message pump
while GetMessage( msg, 0, 0, 0 ) do begin
TranslateMessage( msg );
DispatchMessage( msg );
Look in the forms.pas unit for a more complex message pump.
The main problem with out application is that it's legacy DOS.. And we couldn't refactor the entire thing into an even driven framework without breaking the UI. That would be find and dandy, if the existing ugly DOS UI wasn't effectively an industry standard that 1000's of people understand and now how to use. The need to retrain was a huge factor.
I probably should have qualified 'heavy load'. It's not CPU load, just serial traffic. We are not overrunning any buffers (not even close).
As Stephen mentioned, it is much better to use the OnTriggerAvail event or add a TApdDataPacket component.
That being said, I might have a fix for you.
You should normally use GetChar (or similar command) only within a TriggerAvail event. If you want to use GetChar outside of that event, then you should: 1) Have no other Apd components (besides ApdComPort) defined, 2) Have no TriggerAvail or TriggerData events, and 3) Set TriggerLength to 0. The gist is that we should do either event-based or non-event based data processing in a program but not both at the same time.
Try setting TriggerLength to zero. Please let us know if that fixed your problem.
http://www.TurboControl.com/TPSupport.htm - TurboPower support links
Thanks for the suggestion, I've made that change (as well as checking CharReady rather than InBuffUsed). Usually takes a bit for the problem to manifest.
We're only using TApdComport, created dynamically. Here's the init as it stands now (added TriggerLength := 0):
ThisComm := TAPDComport.Create(nil);
ThisComm.CommNotificationLevel := 0;
ThisComm.TriggerLength := 0;
ThisComm.InSize := InBufSize;
ThisComm.OutSize := OutBufSize;
ThisComm.PromptForPort := FALSE;
ThisComm.TapiMode := tmOff;
ThisComm.ComNumber := PortNum;
ThisComm.Parity := pNone;
ThisComm.Baud := 9600;
ThisComm.StopBits := 1;
ThisComm.DataBits := 8;
ThisComm.HWFlowOptions := ;
ThisComm.Open := TRUE;
Buffers are 2k each, never had a problem with overrun, it's only talking at 9600baud in all cases..
Thanks for the tips.
I'm outta here for the evening, I'll post results first thing in the morning.
Thanks for the help folks! One of the two changes I made fixed the problem, not a hickup running all night!