[Lazarus] Usage of Serial in a testing program?

Bo Berglund bo.berglund at gmail.com
Mon Sep 10 17:30:23 CEST 2018


On Mon, 10 Sep 2018 13:20:35 +0200, Giuliano Colla via Lazarus
<lazarus at lists.lazarus-ide.org> wrote:

>Il 09/09/2018 13:33, Bo Berglund via Lazarus ha scritto:<br>

>>I am writing a testing application for checking out a TCP to Serial
>>bridge component. I am using Lazarus 1.8.0 and fpc 3.0.4 on Windows 7
>>
>>For the serial port handling I found the "built-in" Serial unit
>>described here:
>>http://wiki.freepascal.org/Hardware_Access#FPC_built_in_Serial_unit
>>
>>Now I have a few questions about its usage:
>>
>>1) Serial port name
>>-------------------
>>When opening the port the example does this:
>>
>>str(ComPortNr,tmpstr);
>>ComPortName:= 'COM'+tmpstr+':';
>>serialhandle := SerOpen(ComPortName);
>>
>>So for say port 29 this results in ComPortName 'COM29:'
>>Is this always the case? I have a hunch that for port numbers 1..9 the
>>Windows port naming is different than for higher port numbers...
>>
>>And if I want to port this to Linux, I guess that the name is
>>completely different, but no hint is given.

>Here is the procedure I'm using to fill up a combo box with the
>names of the existing serial devices on the platform. Please note
>the different naming conventions in Linux and Windows. Also note
>that to report a serial port as existing a test is made to open it
>(using the fpc serial function), and avoid "phantom" ports.

But does not this listing fail if a port is already in use, i.e. the
SerOpen() call will return 0 indicating it is not found?

>procedure TForm1.btnScanPortClick(Sender: TObject);
>var
> PortNr: Integer;
> PortName: String;
> PortHandle: TSerialHandle;
>begin
>  cbSelPort.Items.Clear;
>  cbSelPort.Text:= '';
>{$IFDEF MSWINDOWS}
>  for PortNr := 1 to 9 do begin
>    PortName := 'COM' + IntToStr(PortNr);
>    PortHandle := SerOpen('\\.\'+PortName); //<= Fail if already open?
>    if PortHandle > 0 then begin
>      cbSelPort.Items.Add(PortName);
>      SerClose(PortHandle);
>      if cbSelPort.Text = '' then begin
>        cbSelPort.Text:=PortName;
>        PortSel.Caption:= PortName;
>        end;
>      end;
>    end;
>{$ELSE}
>  for PortNr := 0 to 9 do begin
>    PortName := '/dev/ttyS' + IntToStr(PortNr);
>    PortHandle := SerOpen(PortName);
>    if PortHandle > 0 then begin
>      if cbSelPort.Text = '' then begin
>        cbSelPort.Text:=PortName;
>        PortSel.Caption:= PortName;
>        end;
>      cbSelPort.Items.Add(PortName);
>      SerClose(PortHandle);
>      end;
>    end;
>  for PortNr := 0 to 9 do begin
>    PortName := '/dev/ttyUSB' + IntToStr(PortNr);
>    PortHandle := SerOpen(PortName);
>    if PortHandle > 0 then begin
>      if cbSelPort.Text = '' then begin
>        cbSelPort.Text:=PortName;
>        PortSel.Caption:= PortName;
>        end;
>      cbSelPort.Items.Add(PortName);
>      SerClose(PortHandle);
>      end;
>    end;
>{$ENDIF}
>end;

This seems only to deal with ports 1..9, what about the higher
numbered ports 10..255?
And would it not be a long execution time for testing all 255 possible
com ports on Windows?

>>2) Blocking send?
>>------------------
>>Is this port blocking for sending?
>>
>>The example has this:
>>
>>status := SerWrite(serialhandle, s[1], writecount );
>>
>>where s is a string holding the text to send (I will actually need to
>>use a TBytes array instead) and writecount returns the bytes actually
>>sent.
>>
>>If I want to send an array of say 100 kbytes at 9600 baud, will the
>>call return only when the data have been completely sent or earlier?
>>It will take about 100 seconds to send that array...


>Yes, SerWrite is blocking.

Does this mean that it is actually waiting for the data to be
physically sent out on the wire or until the operating system transmit
buffer has absorbed all of the data?
If the latter then a possibility to resize the transmit buffer would
help. But how?

>I hope you don't plan to send 100 kbytes
>in a single write on a serial line. The probability of an error in
>between is near to 100%!<br>
>What I'm doing in such cases is to create a dedicated thread to
>handle send and receive, without blocking the main thread, which
>remains responsive, and split the send in many small blocks (and
>getting some sort of ACK/NAK from remote receiver), which makes it
>possible to show a progress bar or whatever visual feedback you
>like.

Unfortunately not possible in the real case because the file transfer
protocol of the device only sends a header with the count of the data
to follow and then streams all of the bytes....


>>3) Receiving data
>>----------------
>>For data reception I see this:
>>
>>s:='';
>>ComIn:='';
>>while (Length(Comin)<10) and (status>=0) and not keypressed do 
>>begin
>>   status:= SerRead(serialhandle, s[1], 10);
>>   ...
>>
>>Since the call parameters are the receive buffer and the count to read
>>I do not understand how this can work. s has been emptied (length = 0)
>>just before the call so how can SerRead stuff any data into the buffer
>>starting at s[1], which should not even exist???
>>
>>I would like to have a way to read incoming data asynchronously so I
>>also could handle the user feedback and the TCP connection which is
>>sending the data that ultimately will arrive on the serial line...
>>
>>Any suggestions on how to do this?

>I never use SerRead, but rather SerReadTimeout (from the same
>unit) which gives a much better control of what is going on. Of
>course in that case your receiving buffer must be large enough to
>accommodate the largest block you expect. (This replies also to
>your further questions).

Did not see this before, but it seems like a good choice for reading
data in a loop until the return is less than Count, which means that
the timeout has caused the exit.
Thanks for the suggestion!


>I hope that it helps.
Yes it does, but it would have been even better if not full of HTML
tags and stuff. I have edited out most but I guess there are some
still left...
For example inside the code there may be some things like > rather
than >


-- 
Bo Berglund
Developer in Sweden



More information about the Lazarus mailing list