I think there may be a solution with this performance counter for my purposes…  
here’s what I’m trying to accomplish:

 

I’m trying to read a string from a serial port until I get a linefeed, but I 
don’t want it to get stuck in an endless loop which could happen if:

A: nothing is ever received

B: garbage is being received due to bad connection or baudrate mismatch.. etc..

So I keep reading the port in a loop until

A:  I try 10 times and still get nothing

B:  I get the data I’m looking for ending with a #10 

C:  I get too much data, then I stop after 254 bytes, the response should never 
be that long, so I’ll flag that as garbage.

D: I try 1000 times and still do not have a #10 but I also do not have 254+ 
bytes

 

For fast baud rates, this works fine, but for slow baudrates, I reach 1000 
tries way before the string is finished, so I planned on putting in a delay 
calculated from the baudrate… however I think I can take a different approach 
here.  I don’t really care the exact amount of time between retries, I just 
want to try for a long enough length of total time before giving up, so I don’t 
get stuck in a loop.   Perhaps I can read   QueryPerformanceCounter(ct); during 
the loop and if it exceeds the set amount of time, then use that to end the 
loop and give up.   

 

Here’s my function as it is.. fyi, my entire project is in turbo pascal 
compatibility mode:

 

Function ReadSerial(SerPortNum:Byte):String;

Var

   Loopcount:Word;

   CharCount:Byte;

   InputString:String;

   InputLetter:Char;

Begin

   LoopCount:=0;

   CharCount:=0;

   InputString:='';

   repeat

      Status:= SerRead(SerialHandle[SerPortNum], Inputletter, 1);

      if (status > 0) {and ((InputLetter<>#10) AND (InputLetter<>#13))} then

           begin

              Inc(CharCount);

              case InputLetter of

                  ' ':InputString:=InputString+'.';

                  #10:InputString:=InputString+'#10';

                  #13:InputString:=InputString+'#13';

              else

                 InputString:=InputString+(InputLetter);

            end;

         end;

      Inc(Loopcount);

      {need delay here for slow baud rates}

    Until (InputLetter=#10) OR ((Loopcount>10) AND (InputString='')) OR 
(CharCount>254) OR (Loopcount>1000);

    ReadSerial:=InputString;

end;

 

 

From: fpc-pascal-boun...@lists.freepascal.org 
[mailto:fpc-pascal-boun...@lists.freepascal.org] On Behalf Of Dmitry Boyarintsev
Sent: Tuesday, July 26, 2016 1:05 PM
To: FPC-Pascal users discussions <fpc-pascal@lists.freepascal.org>
Subject: Re: [fpc-pascal] Microsecond Delay Suggestions?

 

On Tue, Jul 26, 2016 at 12:38 PM, James Richters 
<ja...@productionautomation.net <mailto:ja...@productionautomation.net> > wrote:

What I need is a timer that I can specify in microseconds, a millisecond is too 
long.   I am using it for timing to read in a string on a serial connection.  
My fastest baudrate is 250000, so at that rate I would need to delay only 36 
microseconds.  So I can’t use sleep () or delay () because they only go down to 
1mS and that’s too slow.

 

Here's an example of Sleep with microseconds that I came up with 


procedure SleepMcs(mcs: Int64);
var
  ct : TLargeInteger;
  fr : TLargeInteger;
  af  : TLargeInteger;
  trg : TLargeInteger;
const
  NanoInMicro = 1000;
begin
  QueryPerformanceCounter(ct);
  QueryPerformanceFrequency(fr);
  trg:=round(mcs * NanoInMicro / (NSInSec/fr));
  repeat
    QueryPerformanceCounter(af);
  until trg<=(af-ct);
end;

I'm hoping that there's a better solution out there, because this procedure 
will end up with 100% CPU load.

I doubt it's possible to unload the CPU, since the windows scheduler is in 
milliseconds accuracy.

May be a lower (kernel/driver) level allows that.

 

thanks,

Dmitry 

 

_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to