Re: [fpc-pascal] Reading Serial Hex Data

2020-12-28 Thread José Mejuto via fpc-pascal

El 28/12/2020 a las 2:02, James Richters via fpc-pascal escribió:

I think I figured out why my writeln's are causing an issue.. they are 
introducing a delay between the SerWrite and SerRead...
and the device I am reading is timing out and sending it's response a second 
time.


Hello,

None of the serial devices I have seen do something like that, in fact 
usually they do exactly the opposite, fire and forget, or in other words 
send a message and do not check for errors unless they wait for an 
answer from the host.


Your problem seems to be or a documentation misinterpretation or the 
connection or the device is not using any kind of flow control.



I was under the impression that there was a hardware buffer on the serial 
ports, my packets are very small,
some only a few bytes, but even those are not going into any kind of a hardware 
buffer.


Hardware buffers in serial device is 16 bytes (In fact 14 for receive) 
at most and it is managed by the Windows serial driver to garantee no 
byte is lost. The operation scheme is something like:


1- Serial byte received
2- IRQ signal issued
3- Windows serial driver read serial port and copy byte(s) to driver buffer.
4- Signal IRQ as handled.

The 16 bytes hardware (FIFO) buffer is present to garantee that if steps 
between 2 and 4 takes too much time (this is time scaled in 1990's CPU 
power) no byte is lost. If an Intel 8088 can read 115200bps without any 
byte lost think what a today computer can read.


In order to perform tests there are programs where you create an hex 
string to be sent and inspect the answer from the device. Read 
documentation about how to open the port, specially about the flow 
control sync. XOn/XOff, RTS/CTS. In example some need that you raise the 
RTS line and wait for CTS line to be high before write, if you do not 
wait the device can misinterpret your request and hang or answer 
something stupid, this is automatically done by the Windows serial 
driver if you select the RTS/CTS flow control when open the port.



Have a nice 2021!

--

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Reading Serial Hex Data

2020-12-28 Thread Bo Berglund via fpc-pascal
On Mon, 28 Dec 2020 14:12:02 +0100, Jean SUZINEAU via fpc-pascal
 wrote:

>Le 28/12/2020 à 13:16, Bo Berglund via fpc-pascal a écrit :
>>  Synchronize(CallEvent); //Supply received data in FBuffer to
>> caller
>
>You are using TThread.Synchronize.
>
>In a console app, it's likely that somewhere else in your main thread 
>you'll need to call regularly Classes.CheckSynchronize to allow the 
>actual execution of CallEvent.
>
>In my case, linux server dll called by a 4js 4GL console program (no GUI 
>on linux server), I need to call regurlarly Classes.CheckSynchronize 
>froml 4gl through function exported by the pascal code.
>If I don't do this, the CallEvent is nether called.
>

Where I use the fpserial class for communications over RS232 there is
an "eternal" loop in the main program, which for a console program is
what is really running:

{$IFDEF UNIX} //What to do for system messages
procedure handleSignal(signum: CInt); cdecl;
begin
  case signum of
SIGHUP : bSHup := true;
SIGTERM : bSTerm := true;
SIGINT : bSInt := true
  end;
end;
{$ENDIF}

program
  //Create all objects and start processes
  
  {$IFDEF UNIX} //Make sure there is a signal handler
fpSignal(SigTerm, SignalHandler(@handleSignal));
fpSignal(SigInt, SignalHandler(@handleSignal));
fpSignal(SigHup, SignalHandler(@handleSignal));
  {$ENDIF}
  //Now wait for signals:
  While not (bSTerm or bSInt or bsHup) do //React to system signals
  begin
//Here is where the server runs as defined elsewhere
//Eternal loop to wait for system messages
Sleep(1); //To not hog the CPU
CheckSynchronize; //Enable events to fire off handlers
  end;
  //cleanup and exit
  ...
end.

The program is intended to run as a Linux service and so it reacts to
the service manager's messages which are coming in via the
handleSignal procedure.

The main action is controlled by socket handlers started by the
preliminaries in the main program and which are triggered by events
from various sources like TCP/IP connections, timers etc.


-- 
Bo Berglund
Developer in Sweden

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Reading Serial Hex Data

2020-12-28 Thread Jean SUZINEAU via fpc-pascal

Le 28/12/2020 à 13:16, Bo Berglund via fpc-pascal a écrit :

 Synchronize(CallEvent); //Supply received data in FBuffer to
caller


You are using TThread.Synchronize.

In a console app, it's likely that somewhere else in your main thread 
you'll need to call regularly Classes.CheckSynchronize to allow the 
actual execution of CallEvent.


In my case, linux server dll called by a 4js 4GL console program (no GUI 
on linux server), I need to call regurlarly Classes.CheckSynchronize 
froml 4gl through function exported by the pascal code.

If I don't do this, the CallEvent is nether called.

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Reading Serial Hex Data

2020-12-28 Thread Bo Berglund via fpc-pascal
On Sun, 27 Dec 2020 18:20:32 -0500, James Richters via fpc-pascal
 wrote:
>>On Sun, 27 Dec 2020 10:47:59 -0500, James Richters via fpc-pascal 
>> wrote:
>>
>>>I'm trying to figure out how to read a packet of HEX Bytes of an 
>>>unknown length that have no specific termination character over a 
>>>serial port as efficiently as practical.
>>
>>What exactly do you mean by HEX Bytes?
>>Hex transfers using two characters for each byte? like 1F A4 etc?
>
>What I meant by 'Hex Data'  is that I am reading data in the form of bytes but 
>they do not represent ASCII characters.  
>So if I read a $0D,  it's just a byte $0D, it doesn't represent a carriage 
>return.  There is no specific code for end of line, 
>the last two bytes are a checksum, but I won't know they are the last ones 
>until I'm done reading.  
>I'm reading all the data available, then analyzing it.
>

This is NOT wahat is generally meant by hex data, hex data means bytes
are encoded using the ASCII characters 0..9, A..F thus expanding data
size by x2 while making it possible to send over channels that use
control characters to handle transfer details such as line feeds,
start of text and end of text etc.
What you have is straight binary data

>>
>>Is your program a console or GUI program?
>
>This is a console application.

I suspected as much. Many of the serial components available are
geared towards GUI apps and so for instance LazSerial links in stuff
like Forms and menus and the like, which causes exceptrions when
running in a straight GUI-less environment like a Linux server.

So I created a class named fpserial where I packaged the functions I
needed and used the built-in Serial unit as the basic execution
handler.

This class uses an event model to supply incoming data, which are
received inside a thread and supplied via a synchronized call to the
event function in the main thread of the program.
Being a console program it has a loop which includes CheckSynchronize
to handle this.

After I did that I have had no problems talking to external hardware
sending and receiving data in binary streams.

But there is a "protocol" for the transfers implemented to allow some
control. It looks something like this:

Where length is a 4-byte integer containing the length of the transfer
body and checksum is a 16 bit sum over all of the bytes inside the
body (excluding the checksum).

The messages are sent following a handshake between the two sides.

My thread code looks like this:

  { TComPortReadThread }

  TComPortReadThread=class(TThread)
  private
FBuffer: TBytes;
FReadPacketSize: integer;
FReadTimeout: integer;
  public
MustDie: boolean;
Owner: TFpSerialPort;
property ReadPacketSize: integer read FReadPacketSize write
FReadPacketSize; //How many bytes to read in each operation
property ReadTimeout: integer read FReadTimeout write
FReadTimeout;//Max time to wait for data in thread
  protected
procedure CallEvent;
procedure Execute; override;
  published
property Terminated;
  end;

implementation

{ TComPortReadThread }

procedure TComPortReadThread.CallEvent;
begin
  if Assigned(Owner.FOnRxData) then
  begin
Owner.FOnRxData(Owner, FBuffer);
  end;
end;

procedure TComPortReadThread.Execute;
var
  Cnt: integer;
begin
  try
SetLength(FBuffer, BUFFERSIZE); //Set buffer size to 8192 bytes.
while not MustDie do
begin
  cnt := SerReadTimeout(Owner.FHandle, FBuffer[0],
FReadPacketSize, FReadTimeout); //Read FReadPacketSize bytes with
timeout of FReadTimeout ms
  if  cnt > 0 then
  begin
SetLength(FBuffer, cnt); //Reduce size to fit received data
Synchronize(CallEvent); //Supply received data in FBuffer to
caller
SetLength(FBuffer, BUFFERSIZE); //Reset buffer size to 8192
bytes.
  end;
end;
  finally
Terminate;
  end;
end;


HTH

-- 
Bo Berglund
Developer in Sweden

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Reading Serial Hex Data

2020-12-28 Thread Marco van de Voort via fpc-pascal


Op 12/27/2020 om 4:47 PM schreef James Richters via fpc-pascal:

I'm trying to figure out how to read a packet of HEX Bytes of an unknown
length that have no specific termination character over a serial port as
efficiently as practical.
The packet ends when there is just no more data to read.

I have something that is working that I wrote using SerRead from the Serial
unit in FPC, and it works at 9600bps,
but the method I am using will not work well at anything higher unless I can
figure out how to a very accurate very short delay.
At 9600, I need a delay just a little less than 1ms, so I use Sleep(1) for
my delay, but since 1ms is the minimum for sleep, and sleep
itself is not really that accurate, I am doing a lot more delay than I need
to in order to make sure it works.


You don't mention OS, but for Windows no sleep should not be necessary, 
and is unnecessarily delaying.


Look at delphi tcomport which has a waitforevent based solution.

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal