[fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?

Bo Berglund bo.berglund at gmail.com
Mon Aug 31 09:38:08 CEST 2020


On Fri, 21 Aug 2020 21:03:31 +0200, Bo Berglund via fpc-pascal
<fpc-pascal at lists.freepascal.org> wrote:

>Instead I need to add a thread for reading data so I can have an event
>driven reception of data. It would read available data and fire off a
>NotifyEvent to handle the incoming data in the main application.

I have now started to implement a simple "fpserialport" class using
the built-in serial unit and I am trying to add a reading thread so I
can get an OnRxData event which is needed by many of the non-GUI
applications I want to port to Fpc/Lazarus.

It can be a simple TNotifyEvent where the user will implement the
actual read or else a specific event procedure providing a TBytes
container with the data. Both are possible.

But when doing this I have run into a problem, how can I check how
many Rx bytes are available to be read from the operating system?

If I simply use the SerReadTimeout() function it will return either
with 1 or more bytes or after the timeout. But there is a problem
here:

function SerReadTimeout(Handle: TSerialHandle; var Buffer; mSec:
LongInt): LongInt;

When calling this the Buffer length has to be set *beforehand* so the
arriving data can fit inside the buffer, but how can I know how big
Buffer must be?
I assume that if the Buffer is too small there will be an exception or
else an overwrite of following memory?

The other variant of the read:

function SerReadTimeout(Handle: TSerialHandle; var Buffer: array of
byte; count, mSec: LongInt): LongInt;

Here there is a count argument that will limit the amount of data read
into the buffer, but from the code in serial.pp it seems like the
function can in fact read more data into the buffer than count. The
break condition is:

  while fpSelect(Handle + 1, @readSet, nil, nil, @selectTimeout) > 0
do begin
    Inc(result,fpRead(Handle, Buffer[result], count - result));
    if result >= count then // <== HERE possible overflow
      break;
    if Assigned(SerialIdle) then
      SerialIdle(Handle)
  end


Is there a possibility to create a function that checks how many bytes
are available in the operating system buffer and then dimension the
buffer using this value and read only that count?

Something like:

function SerInbytesWaiting(Handle: TSerialHandle): LongInt;

Then the read can be done using this value to get the exact number of
bytes into the properly dimensioned buffer, which can then be provided
to the event procedure as a TBytes container.

I know too little about the operating system inner workings to be able
to do this myself...


-- 
Bo Berglund
Developer in Sweden



More information about the fpc-pascal mailing list