Recent

Author Topic: Porting Delphi application to Lazarus then Linux, what about serial comm?  (Read 7014 times)

BosseB

  • Sr. Member
  • ****
  • Posts: 468
I use TComport on both Delphi (XE10-seattle) and FPC, but in both cases only on win32/64
That is the problem, in order to port I need:
1) An event driven serial component (non-blocking to the user)
2) A component that works on both Windows and Linux
3) As seen here it must be compatible with an ARM processor...

I hope the fix found today will make it work on Raspbian Linux.

I have pulled the serial comm part out into a test application, which I will check out on RPi later today.

--
Bo Berglund
Sweden

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
the original author is "Jurassic Pork". Send him a PM, and hopefully he will fix it.
THanks,
I have just sent him a message about this.
Hopefully he will correct the file and post a package update.
His last activity in this forum was in February. So if you don't get a reply try to report a bug at https://github.com/JurassicPork/TLazSerial.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

BosseB

  • Sr. Member
  • ****
  • Posts: 468
the original author is "Jurassic Pork". Send him a PM, and hopefully he will fix it.
Thanks,
I have just sent him a message about this.
Hopefully he will correct the file and post a package update.
His last activity in this forum was in February. So if you don't get a reply try to report a bug at https://github.com/JurassicPork/TLazSerial.
In fact I got connected to the OPM maintainer and he asked me to send him the modified package to him, which I did.
He has updated OPM with this now so in the future we will not need to do this correction manually when installing on Raspberry Pi.
Just checked with an older Lazarus (2.0.4 on RPi).

--
Bo Berglund
Sweden

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
hello BosseB,
can you you try this more readable code for your modification :
Code: Pascal  [Select][+][-]
  1. const
  2. {$IF (DEFINED(UNIX)) AND (NOT (DEFINED(CPUARM))) }
  3.   {$IFDEF DARWIN}
  4.   MaxRates = 18;  //MAC
  5.   {$ELSE}
  6.    MaxRates = 30; //UNIX
  7.   {$ENDIF}
  8. {$ELSE}
  9.   MaxRates = 19;  //WIN  and Raspberry Pi
  10. {$ENDIF}
  11.   Rates: array[0..MaxRates, 0..1] of cardinal =
  12.   (
  13.     (0, B0),
  14.     (50, B50),
  15.     (75, B75),
  16.     (110, B110),
  17.     (134, B134),
  18.     (150, B150),
  19.     (200, B200),
  20.     (300, B300),
  21.     (600, B600),
  22.     (1200, B1200),
  23.     (1800, B1800),
  24.     (2400, B2400),
  25.     (4800, B4800),
  26.     (9600, B9600),
  27.     (19200, B19200),
  28.     (38400, B38400),
  29.     (57600, B57600),
  30.     (115200, B115200),
  31.     (230400, B230400)
  32. {$IFNDEF DARWIN}
  33.     ,(460800, B460800)
  34.   {$IF (DEFINED(UNIX)) AND (NOT (DEFINED(CPUARM)))} //Not for RPi with ARM CPU
  35.     ,(500000, B500000),
  36.     (576000, B576000),
  37.     (921600, B921600),
  38.     (1000000, B1000000),
  39.     (1152000, B1152000),
  40.     (1500000, B1500000),
  41.     (2000000, B2000000),
  42.     (2500000, B2500000),
  43.     (3000000, B3000000),
  44.     (3500000, B3500000),
  45.     (4000000, B4000000)
  46.   {$ENDIF}
  47. {$ENDIF}
  48.     );
  49. {$ENDIF}
  50. {$IFDEF DARWIN}
  51. const // From fcntl.h
  52.   O_SYNC = $0080;  { synchronous writes }
  53. {$ENDIF}

I will update my github project if it is OK

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

BosseB

  • Sr. Member
  • ****
  • Posts: 468
I replaced the section in lazsynaser.pas starting at about line 220 with the code you showed above.
Then I opened the package in Lazarus 2.0.8 and compiled it and it succeeded.
(I first made an intentional error in the file too just to check that the compile would fail and it did.)
So I guess that version is OK. Except I have only tested on Raspberry now.

Note that Balázs has published the package with my changes on OPM yesterday.
You might want to get him repeat with whatever package changes you send to him.
--
Bo Berglund
Sweden

BosseB

  • Sr. Member
  • ****
  • Posts: 468
One observation:
I noted when I switched between Windows and Raspbian that on line 173 there is a conditional
Code: Pascal  [Select][+][-]
  1. {$IFNDEF MSWINDOWS}
which closes way down on the line just above this in your code
Code: Pascal  [Select][+][-]
  1. {$IFDEF DARWIN}

The effect of this is that the comment on this line which is inside that conditional seems not really valid:
Code: Pascal  [Select][+][-]
  1. MaxRates = 19;  //WIN  and Raspberry Pi
because you cannot get here if you are on Windows at all....
On Windows all this is disabled by the conditional..

--
Bo Berglund
Sweden

PaulRowntree

  • Full Member
  • ***
  • Posts: 132
    • Paul Rowntree
J.P. was kind enough to add a new br_28800 baud rate for a specialized piece of equipment (no flexibility on the baud rate) that I have running under Windows.  Works perfectly.  I don't see that value in the list that was posted ....
Is br_28800 still available?Would there be a flexible way to add br_custom to allow unusual baud rates in the future?
Thanks!
Paul Rowntree
- coding for instrument control, data acquisition & analysis, CNC systems

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
BosseB ,
MaxRates is only used for Unix , i don't know why there was a // win comment in the code. It is not me who has done this comment.
PaulRowntree, i will take a look about your note.

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

ccrause

  • Hero Member
  • *****
  • Posts: 845
Would there be a flexible way to add br_custom to allow unusual baud rates in the future?
It is possible at least for Windows and Linux, see e.g. https://github.com/ccrause/debugwire-gdb-bridge/blob/master/serialutils.pas#L78
This should probably sit in FCL, not a higher level component.

BosseB

  • Sr. Member
  • ****
  • Posts: 468
The way I see it implemented in lazsynaser.pas is that it uses constants defined in rtl/linux/termios.inc in the fpc compiler sources.
I cannot find any reference there to 28800 so it would not be straightforward to fix.
But this termios.inc file does only get in play if we are on UNIX, so if 28800 is needed in Windows then it must be defined elsewhere.
--
Bo Berglund
Sweden

BosseB

  • Sr. Member
  • ****
  • Posts: 468
A general porting question:
If I prepare the original sources prior to conversion to Lazarus by putting in conditionals for handling the serial port such that it looks somewhat like this:
Code: Pascal  [Select][+][-]
  1. {$IFDEF USE_LAZSERIAL}
  2. //Code pertaining to LAZSERIAL
  3. {$ELSE}
  4. //Code pertaining to AsyncPro or some other serial implementation
  5. {$ENDIF}
  6.  
Will the converter then pick up the defines I have set myself?
Note that these defines are set in the Delphi 2007 menu
project/options/directories-conditionals

Or do I have to explicitly define them in Delphi startup code (in that case where)?

I have found a number of candidates for removal other that just the AsyncPro stuff, which I use conditionals to disable in order to verify that the code builds both with the conditional and without it.
But will it work with the Lazarus Delphi converter?
--
Bo Berglund
Sweden

BosseB

  • Sr. Member
  • ****
  • Posts: 468
Is there any method for LazSerial to flush the indata buffer?
I want to get rid of the content of the buffer if it contains something before I start over with a new transaction.
AsyncPro has a method FlushInBuffer and the other Windows only serial component also has one named ZapRxQueue

Is something like that available for LazSerial too?

Or do I have to do:
Code: Pascal  [Select][+][-]
  1. procedure FlushRxData;
  2. var
  3.   tmp: string;
  4. begin
  5.   if FComm.DataAvailable then
  6.     tmp := FComm.ReadData();
  7. end;
  8.  

And is there any way to monitor the outdata buffer so that the code can know when all data have been transferred?
In the existing code using Async Pro I have this to monitor the progress of the slow transmission:
Code: Pascal  [Select][+][-]
  1. repeat
  2.   {send data in chunks of 512 bytes}
  3.   sBuf := Copy(Cmd, 1, 512);
  4.   Delete(Cmd,1,512);
  5.   FComm.PutString(sBuf);
  6.   while FComm.OutBuffUsed > 16 do //Wait until most data sent
  7.   begin
  8.       Application.ProcessMessages;
  9.       Sleep(1);
  10.   end;
  11.   SetProgress(p - Length(Cmd), -1);
  12. until  Cmd = '';
  13.  
I looked in the LazSerial unit and could not find anything similar to OutBufferUsed...
The other serial component also has a similar function named TxWaiting.
Any suggestions as to how I can deal with this?
« Last Edit: May 09, 2020, 11:12:21 am by BosseB »
--
Bo Berglund
Sweden

sstvmaster

  • Sr. Member
  • ****
  • Posts: 299
You can look into the SynSer property, there are many procedures and functions from Synaser.

Code: Pascal  [Select][+][-]
  1. FComm.SynSer.xxx
greetings Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
hello,
as suggested by jamie , use SendingData (in your case FComm.SynSer.SendingData) to see number of bytes waiting to be sent :
Quote
function SendingData: integer; virtual;
Returns the number of bytes waiting to be sent in the output buffer. 0 is returned when the output buffer is empty.

and Flush (in your case FComm.SynSer.Flush()) to wait until all data to is sent.
Quote
procedure Flush; virtual;
Waits until all data to is sent and buffers are emptied. Warning: On Windows systems is this method returns when all buffers are flushed to the serial port controller, before the last byte is sent!

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

BosseB

  • Sr. Member
  • ****
  • Posts: 468
hello,
as suggested by jamie , use SendingData (in your case FComm.SynSer.SendingData) to see number of bytes waiting to be sent :
Quote
function SendingData: integer; virtual;
Returns the number of bytes waiting to be sent in the output buffer. 0 is returned when the output buffer is empty.
OK, thanks. I have added this to the function (it is now in a conditional compile block in preparation for being ported):
Code: Pascal  [Select][+][-]
  1.       {$IFNDEF FPC} //Delphi
  2.         {$IFDEF USE_ASYNCPRO}
  3.           while FComm.OutBuffUsed > 16 do
  4.         {$ELSE}
  5.           while FComm.TxWaiting > 16 do
  6.         {$ENDIF}
  7.       {$ELSE}  //FPC using LazSerial
  8.           while FComm.SynSer.SendingData > 16 do
  9.       {$ENDIF}
  10.           begin
  11.             Application.ProcessMessages;
  12.             Sleep(1);
  13.           end;
  14.  
Quote
and Flush (in your case FComm.SynSer.Flush()) to wait until all data to is sent.
Quote
procedure Flush; virtual;
Waits until all data to is sent and buffers are emptied. Warning: On Windows systems is this method returns when all buffers are flushed to the serial port controller, before the last byte is sent!

Friendly, J.P
Well, that "Waits" sort of makes the system blocking, which is not what I want.
The code originates from long ago (2004) and it is not threaded apart from what a Delphi program itself provides.
Instead it is event driven.
During long serial transfers it therefore uses the construct above including the Application.Processmessages call to allow for the events to happen while the transfer is running on the serial port.
In some cases this could take many seconds up to more than a minute...
« Last Edit: May 12, 2020, 10:34:46 am by BosseB »
--
Bo Berglund
Sweden

 

TinyPortal © 2005-2018