We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

Loosing Bytes under WinNT serial port

eeks2
eeks2 asked
on
Medium Priority
317 Views
Last Modified: 2013-12-03
Problem:

Loosing bytes under WindowsNT 4.0 Service Pack 3 when reading from a serial port.

Description:

I have an external datasource which responds immediately after sending bytes.
The program I wrote to communicate with the external datasource works fine under Windows95, but under WinNT some bytes of the response do not appear in the inputqueue.
The communication does not run very quickly. (19200 Baud, Even Parity, 1 Stop)
Fifo is enabled.
During my investigations I found out that the bytes collected by the serial port are transferred very slowly to the inputqueue under WinNT.
The whole communication is programmed to run in an extra thread.
The program is not written eventdriven, because then it reacts too slow.

Basic communication routines in serial.cpp are :
TComm::InitCommDriver
TComm::Write
TComm::Read

example routine in comthr.cpp:
TCommands::ExtendedCommand

Question:

What do I have to do, that the system does not loose bytes.
Can I tune the Comport in system initialisation?
Comment
Watch Question

Commented:

You say you are running the "communication" in an extra thread.  Is this just the character receive routine or is there other stuff going on?  If you are doing something like this, you should minimize the amount of code in the loop.  Also, what priority level have you set for this thread.  It may be getting pushed too far down in the priority to get enough time to run.  

Does your hardware have a 16550 UART with FIFO?  If not, get one that does and make sure it's enabled.  NT (as well as most other multi-processing operating systems) has trouble with real-time events and ensuring that they get processed in a specified time.  In your case, incoming characters are real-time and when the input buffer is full, you must get the data or it will be lost.  When you read the input stream, make sure you keep reading it until it's empty.  If you just grab the first character and process it, you may be leaving the queue almost full.

Author

Commented:
Dear jhance

I am sorry I know about these problems in multitasking environments.
I try to read the whole queue, but the bytes are simply not in it.
I tried all kinds of priority-levels, but this has nearly no effect.
The task which reads has no extra code exept a timeoutcontrol.

Commented:
Just figured I'd help humanity by saying 'losing' it spelled with just one O.

Commented:
You need to provide more info -  are the characters being lost at the start of the message, or are they being dropped in the middle? Is there a pattern?

Are you using overlapped IO?

There are so many possibilities, that you need to post the relevant source code if it isn't too long, or pseudo-code at least.

Author

Commented:
I am using non overlapped IO.
I send the bytes with:
WriteFile(HComm,Buffer,Length,&BytesWritten,NULL);
and read the bytes immediately after this with:
Nr_Bytes=Number of Bytes expected
do
{
 ClearCommError(HComm,&Errors,&Stat);
 Bytes_Received=Stat.cbInQue;
}
while(Bytes_Received!=Nr_Bytes);
ReadFile(HComm,Buffer,Nr_Bytes,&BytesRead,NULL);

Commented:
If the characters you are losing are at the start of the response, then I would switch to overlapped IO and see if that helps.

I have noticed that with NT is sometimes slow to realize that a serial Write is complete, and the response will start coming in before NT reports the transmission has completed. I am using overlapped IO so this is no real problem, but maybe a similar thing is happening to you, except that it's just slow to return from the WriteFile and therefore misses the start of the response.

It depends on what characters are being dropped: if they aren't at the start of the message, that can't be it. Check and see. Making the operation overlapped isn't so tough, anyway, and the code you have above will still work (after adding the overlapped structure to the calls).

Good luck!

Author

Commented:
Dear alamo,
thank you for your hints,
I am not losing the first bytes. I tried to change to overlapped IO, it worked but even worse, may be I do not initialize the overlapped structure in a correct way.
My initialisation is as follows:
Overl.Offset=0;
Overl.OffsetHigh=0;
Overl.Internal=0;
Overl.InternalHigh=0;
Overl.hEvent=NULL;

Commented:
Try simply to call ReadFile just like you are doing now, but without looping ClearCommError.
ReadFile will wait until the specified number of bytes is received, and return.
Probably, this ClearCommError makes some troubles (?).

Author

Commented:
Dear Madorsky,

I tried first to use ReadFile only, but the function returned also with fewer bytes than expected, therefore I introduced the waiting loop in order to wait until the queue reaches the expected amount of bytes.
I use following Timeouts.
COMMTIMEOUTS Timo;
Timo.ReadIntervalTimeout=MAXDWORD;
Timo.ReadTotalTimeoutMultiplier=1;
Timo.ReadTotalTimeoutConstant=1;
Timo.WriteTotalTimeoutMultiplier=1;
Timo.WriteTotalTimeoutConstant=1;
SetCommTimeouts(HComm,&Timo);

Commented:
Probably, the problem is in the wrong settings of COM port.
I used this piece of code several times, and it never failed.
Sorry, it's in Pascal:

    ComHandle := CreateFile
    (
        'COM1', GENERIC_READ or GENERIC_WRITE,
        0, nil, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, 0
    );
    if ComHandle = INVALID_HANDLE_VALUE then
       raise ECC232.Create('Create File failed');
    SetupComm(ComHandle, 2048, 2048);
    CC.dwSize := SizeOf(TCommConfig);
    CC.wVersion := 1;
    CC.dwProviderSubType := PST_RS232;
    CC.dwProviderOffset := 0;
    CC.dwProviderSize := 0;

     with CC do
     begin
         DCB.DCBlength:=SizeOf(Tdcb);
         DCB.BaudRate:= 57600; // set your speed here
         DCB.Flags:=2;
         DCB.wReserved:=0;
         DCB.XonLim:=0;
         DCB.XoffLim:=0;
         DCB.ByteSize:=8;
         DCB.Parity:=2;
         DCB.StopBits:=2;
         DCB.XonChar:=#0;
         DCB.XoffChar:=#0;
         DCB.ErrorChar:=#0;
         DCB.EofChar:=#0;
         DCB.EvtChar:=#0;
         DCB.wReserved1:=0;
         if not SetCommState(ComHandle, DCB) then raise ECC232.Create('SetCommState');
     end;

    SetCommMask(ComHandle, EV_TXEMPTY or EV_RXCHAR);
    PurgeComm(ComHandle, PURGE_TXCLEAR);
end;


Author

Commented:
Dear Madorsky,

my initialisation is very similar to yours, nevertheless I tried extactly your configuration, but the result was not sufficient.

The serial communication fails even more when other programs are running or getting started, so it seems that the multitasking of WindowsNT does not handle threads in a correct manner, because under Windows95 it does not matter which other programs are running or getting started.

Author

Commented:
Dear Madorsky,

please contact me again, due to your hints I found the solution.
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Commented:
So what did the problem turn out to be?

Author

Commented:
Your hint that the ReadFile-function waits until the bytes are collected and that it might be the initialisation of the port led me to the right track. I checked the timeout-structure again and found following solution:

COMMTIMEOUTS Timo;
Timo.ReadIntervalTimeout=0;
Timo.ReadTotalTimeoutMultiplier=0;
Timo.ReadTotalTimeoutConstant=100;
Timo.WriteTotalTimeoutMultiplier=0;
Timo.WriteTotalTimeoutConstant=100;
SetCommTimeouts(HComm,&Timo);

With Timeout set in this way, the routines work under WindowsNT and Windows95 very well and the functions wait 100 milliseconds to be completed.
Thank You :-)

Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.