Solved

Loosing Bytes under WinNT serial port

Posted on 1998-06-15
15
298 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?
0
Comment
Question by:eeks2
  • 7
  • 3
  • 3
  • +2
15 Comments
 
LVL 32

Expert Comment

by:jhance
ID: 1407788

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.

0
 

Author Comment

by:eeks2
ID: 1407789
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.
0
 
LVL 1

Expert Comment

by:_Zaphod
ID: 1407790
Just figured I'd help humanity by saying 'losing' it spelled with just one O.
0
 
LVL 6

Expert Comment

by:alamo
ID: 1407791
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.
0
 

Author Comment

by:eeks2
ID: 1407792
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);
0
 
LVL 6

Expert Comment

by:alamo
ID: 1407793
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!
0
 

Author Comment

by:eeks2
ID: 1407794
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;
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Expert Comment

by:Madorsky
ID: 1407795
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 (?).
0
 

Author Comment

by:eeks2
ID: 1407796
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);
0
 

Expert Comment

by:Madorsky
ID: 1407797
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;


0
 

Author Comment

by:eeks2
ID: 1407798
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.
0
 

Author Comment

by:eeks2
ID: 1407799
Dear Madorsky,

please contact me again, due to your hints I found the solution.
0
 

Accepted Solution

by:
Madorsky earned 200 total points
ID: 1407800
Glad to hear this :-)
0
 
LVL 6

Expert Comment

by:alamo
ID: 1407801
So what did the problem turn out to be?
0
 

Author Comment

by:eeks2
ID: 1407802
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 :-)

0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

This article shows how to make a Windows 7 gadget that accepts files dropped from the Windows Explorer.  It also illustrates how to give your gadget a non-rectangular shape and how to add some nifty visual effects to text displayed in a your gadget.…
This article surveys and compares options for encoding and decoding base64 data.  It includes source code in C++ as well as examples of how to use standard Windows API functions for these tasks. We'll look at the algorithms — how encoding and decodi…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now