Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On Tue, 1 Sep 2020 20:31:57 +0200 (CEST), Michael Van Canneyt via fpc-pascal wrote: >Yes, but you can only override a virtual constructor. The TThread >constructor is not virtual. I am doing the setup in a different way so I don't have to use Create. My new FpSerialPort works fine now with the simple test application. But now I have to plug it into the larger service app I am porting and I have come across a piece of code where the alternative com port classes used on Windows have a way to check how many bytes are in the outgoing buffer ready to be transfered. The existing code waits until there are less than 16 bytes left to transfer before it fills the Tx buffer with another packet of 512 bytes. In order to do this it checks the state of the Tx buffer: Using LazSerial (Windows and Linux): while FComm.SynSer.SendingData > 16 do (waiting for it to empty) Using AsyncPro (Windows): while FComm.OutBuffUsed > 16 do Using an older but simpler serial comp on Windows: while FComm.TxWaiting > 16 do Is there anything comparable available via the serial unit? I have not found anything so I guess it has to be an addition to get it done The binary data to send can in worst case be 1 Mbytes in size even though normally it varies between 1 and a few hundred bytes per operation. Any suggestions? -- 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] Using built-in serial instead of synaser and the like for Linux console app?
On Tue, 1 Sep 2020, Bo Berglund via fpc-pascal wrote: On Tue, 1 Sep 2020 14:21:44 +0200 (CEST), Michael Van Canneyt via fpc-pascal wrote: You must still set the default value in the constructor. Note that the thread itself has no idea what is the baudrate in use so it cannot calculate the proper value at the start of Execute... And there is no Create method either that I can use. The constructor can always be overridden. I did this: TComPortReadThread=class(TThread) private FBuffer: TBytes; FReadPacketSize: integer; FReadTimeout: integer; public MustDie: boolean; Owner: TFpSerialPort; constructor Create; override; //<= THIS ADDED, GIVES ERROR 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; and the code will not compile: fpserialport.pas(41,17) Error: There is no method in an ancestor class to be overridden: "constructor Create;" So, does TThread not have a constructor I thought all objects had. Yes, but you can only override a virtual constructor. The TThread constructor is not virtual. If you want to introduce a new one just leave away the ; override; Michael. -- Bo Berglund Developer in Sweden ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On Tue, 1 Sep 2020 14:21:44 +0200 (CEST), Michael Van Canneyt via fpc-pascal wrote: >You must still set the default value in the constructor. > >> >> Note that the thread itself has no idea what is the baudrate in use so >> it cannot calculate the proper value at the start of Execute... >> And there is no Create method either that I can use. > >The constructor can always be overridden. > I did this: TComPortReadThread=class(TThread) private FBuffer: TBytes; FReadPacketSize: integer; FReadTimeout: integer; public MustDie: boolean; Owner: TFpSerialPort; constructor Create; override; //<= THIS ADDED, GIVES ERROR 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; and the code will not compile: fpserialport.pas(41,17) Error: There is no method in an ancestor class to be overridden: "constructor Create;" So, does TThread not have a constructor I thought all objects had. -- 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] Using built-in serial instead of synaser and the like for Linux console app?
On Tue, 1 Sep 2020, Bo Berglund via fpc-pascal wrote: On Tue, 01 Sep 2020 10:22:08 +0200, Bo Berglund via fpc-pascal wrote: Maybe I could tie the timeout to the actual baud used? Slower speeds use longer timeout etc? Timeout could be set to the time it takes to transfer the number of bytes to read? And both arguments could be made properties of the class such that the user can tweak performance a bit? I tried to do this: TComPortReadThread=class(TThread) private FBuffer: TBytes; FPacketSize: integer; default 10; FReadTimeout: integer; default 10; public MustDie: boolean; Owner: TFpSerialPort; property ReadPacketSize: integer read FPacketSize write FPacketSize; //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; But I cannot set the default value of the two new fields FPacketSize and FReadTimeout, I get an error in the above code (and variations of the same). Is there no way to declare a property to have a default non-zero value? You must set it on the property: Property property ReadPacketSize: integer read FPacketSize write FPacketSize default 10; Note that this does not actually set the property to the indicated value. It is only a hint for the streaming system: You must still set the default value in the constructor. Note that the thread itself has no idea what is the baudrate in use so it cannot calculate the proper value at the start of Execute... And there is no Create method either that I can use. The constructor can always be overridden. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
Ooops, wrong url, I just learn know that property could belong to a global block... ;-) For classes: https://www.freepascal.org/docs-html/ref/refsu33.html#x86-1080006.7.1 ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
Le 01/09/2020 à 10:49, Bo Berglund via fpc-pascal a écrit : Is there no way to declare a property to have a default non-zero value? I'm not sure but I think the syntax is for this something like property ReadPacketSize: integer read FPacketSize write FPacketSize default 10; Reference: https://www.freepascal.org/docs-html/ref/refse27.html ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On Tue, 01 Sep 2020 10:22:08 +0200, Bo Berglund via fpc-pascal wrote: >Maybe I could tie the timeout to the actual baud used? Slower speeds >use longer timeout etc? Timeout could be set to the time it takes to >transfer the number of bytes to read? > >And both arguments could be made properties of the class such that the >user can tweak performance a bit? I tried to do this: TComPortReadThread=class(TThread) private FBuffer: TBytes; FPacketSize: integer; default 10; FReadTimeout: integer; default 10; public MustDie: boolean; Owner: TFpSerialPort; property ReadPacketSize: integer read FPacketSize write FPacketSize; //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; But I cannot set the default value of the two new fields FPacketSize and FReadTimeout, I get an error in the above code (and variations of the same). Is there no way to declare a property to have a default non-zero value? Note that the thread itself has no idea what is the baudrate in use so it cannot calculate the proper value at the start of Execute... And there is no Create method either that I can use. Any ideas? -- 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] Using built-in serial instead of synaser and the like for Linux console app?
On Mon, 31 Aug 2020 12:01:33 +0200, Bo Berglund via fpc-pascal wrote: >Thanks, I was worried about reading more data than specified. >Now I can let the loop in Execute read say 10 bytes or so with timeout >ane process these, then loop back after firing off the event. Just a follow-up for completeness: I have got it running now and I implemented the fpserialport object such tghta if it is commanded to open the port without an event procedure defined it will provide blocking read functions (overloaded for string vs. TBytes containers). But if the event is defined it will read the data in the Execute function in the read thread and provide the data to the user via the event. Here is the read thread code (BUFFERSIZE is set to $2000): TOnRxDataEvent = procedure(Sender: TObject; const Data: TBytes) of object; 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], 10, 10); //Read 10 bytes with timeout of 10 ms if cnt > 0 then begin SetLength(FBuffer, cnt); //Reduce size to fit rx data Synchronize(CallEvent); //Rx data in FBuffer to caller SetLength(FBuffer, BUFFERSIZE); //Restore buffer size end; end; finally Terminate; end; end; So this will fire the event on every 10 bytes received or after the 10 ms timeout, whichever comes first. No event without data, though. I don't know if this is really OK, my applications are using 38400 and 115200 baud so the 10 bytes will arrive in less than 3 ms at the slower speed. But I could not figure out any better way to implement it, save for firing off the event for every byte arriving, which would cause a lot of calls... Maybe I could tie the timeout to the actual baud used? Slower speeds use longer timeout etc? Timeout could be set to the time it takes to transfer the number of bytes to read? And both arguments could be made properties of the class such that the user can tweak performance a bit? -- 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] Using built-in serial instead of synaser and the like for Linux console app?
On Mon, 31 Aug 2020 11:15:10 +0200 (CEST), Michael Van Canneyt via fpc-pascal wrote: > > >On Mon, 31 Aug 2020, Bo Berglund via fpc-pascal wrote: > >> On Fri, 21 Aug 2020 21:03:31 +0200, Bo Berglund via fpc-pascal >> wrote: >> >> 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? > >There is some ioctl() function for that, but using that is not recommended. > >The normal way of doing is is reading a buffer till no more data >is read and then treat the buffer Yes, but my problem is that I don't know in advance how many bytes there are coming... >> >> 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? > >Serial normally does not handle buffers >4k. OK so if I assign an 8k TBytes buffer inside the read thread and use that then I can copy the buffer data into another TBytes container which is the size of the received data and supply that in the event function. Of course the event must be processed before the thread continues its read attempts, so for that I thought I'd have to use Synchronize() > >since fpRead will never read more than Count bytes >(count-result is always less than count for positive result) result can at >most be Count. > >(if fpRead returns a negative result, the algorithm is simply wrong, the >algorithm assumes the fpRead will always succeed) > >Disregarding the error condition you can perfectly use this function. Thanks, I was worried about reading more data than specified. Now I can let the loop in Execute read say 10 bytes or so with timeout ane process these, then loop back after firing off the event. -- 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] Using built-in serial instead of synaser and the like for Linux console app?
On Mon, 31 Aug 2020, Bo Berglund via fpc-pascal wrote: On Fri, 21 Aug 2020 21:03:31 +0200, Bo Berglund via fpc-pascal 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? There is some ioctl() function for that, but using that is not recommended. The normal way of doing is is reading a buffer till no more data is read and then treat the buffer 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? Serial normally does not handle buffers >4k. I assume that if the Buffer is too small there will be an exception or else an overwrite of following memory? Yes. 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 That seems correct. since fpRead will never read more than Count bytes (count-result is always less than count for positive result) result can at most be Count. (if fpRead returns a negative result, the algorithm is simply wrong, the algorithm assumes the fpRead will always succeed) Disregarding the error condition you can perfectly use this function. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On 31 Aug 2020 at 9:38, Bo Berglund via fpc-pascal wrote: > On Fri, 21 Aug 2020 21:03:31 +0200, Bo Berglund via fpc-pascal > 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. > I have been using the FPC serial unit for some years, and have never experienced any issues. Usually I read data this way (if it is text). I have been using this on both Windows and Linux (Raspberry Pi) for some years. This is a small bit of a specific program that reads answers on an RS485 bus. Carsten Var vSioCnt:integer=0; vRetrySioRead:LongInt=0; vSioBuf:shortstring; vRs485Sio:LongInt=0; repeat vSioCnt:=serial.SerRead(vRs485Sio,vSioBuf[1],255); if vSioCnt>0 then {Has data been read} begin setlength(vSioBuf,vSioCnt); vSioStringS:=vSioStringS+vSioBuf; {Move data into ansi string} vRetrySioRead:=6; {Try in 6/100 if more data is coming} end else if vRetrySioRead<>0 then sleep(10); {Wait for 1/100 sec.} if vRetrySioRead<>0 then dec(vRetrySioRead); until (vSioCnt<=0) and (vRetrySioRead=0); {There was no more data} > Bo Berglund > Developer in Sweden > > ___ > fpc-pascal maillist - fpc-pascal@lists.freepascal.org > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On Fri, 21 Aug 2020 21:03:31 +0200, Bo Berglund via fpc-pascal 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 ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On Fri, 21 Aug 2020 20:06:04 +0200, Christo Crause via fpc-pascal wrote: >In my limited experience the FPC serial unit is a bit more low level than >the components such as synaser etc. There is a bit more of a learning >curve and one needs to decide whether to go blocking or not and how to >handle async reads etc. I needed to use custom baud rates with auto baud >for an application (debugwire-gdb-bridge) so I took the time to figure out >some of the details. >Since then I've re-used it in other serial based >applications - once you get past the learning curve of how things fit >together it is relatively easy (I guess like most things). I prefer it now >because it reduces external dependencies in a project. This is what I am also looking for after having dealt with AsyncPro on Delphi for many years in the beginning of this century. It was never possible to figure out how many of the units one really needed to talk serial... And LazSerial pulls in (unnecessarily) GUI dependencies so it cannot be used in a non-gui application. > >> Seems like there are virtually no posts describing solutions using >> serial... >> > >Here is a unit showing how to open, read and write (blocking) using the >serial unit: >https://github.com/ccrause/debugwire-gdb-bridge/blob/master/serialutils.pas >Unfortunately there is other code for sending a break command and setting >custom baud rates which makes it appear more complicated than it should be. Thank you very much for this! I do not need break or non-standard baudrates so I will cut that away when testing it. 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. -- 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] Using built-in serial instead of synaser and the like for Linux console app?
On Fri, Aug 21, 2020 at 12:05 PM Bo Berglund via fpc-pascal < fpc-pascal@lists.freepascal.org> wrote: > So hence my question: > Is there something bad about serial (built-in to fpc) that makes it > unsuitable for use? > In my limited experience the FPC serial unit is a bit more low level than the components such as synaser etc. There is a bit more of a learning curve and one needs to decide whether to go blocking or not and how to handle async reads etc. I needed to use custom baud rates with auto baud for an application (debugwire-gdb-bridge) so I took the time to figure out some of the details. Since then I've re-used it in other serial based applications - once you get past the learning curve of how things fit together it is relatively easy (I guess like most things). I prefer it now because it reduces external dependencies in a project. > Seems like there are virtually no posts describing solutions using > serial... > Here is a unit showing how to open, read and write (blocking) using the serial unit: https://github.com/ccrause/debugwire-gdb-bridge/blob/master/serialutils.pas Unfortunately there is other code for sending a break command and setting custom baud rates which makes it appear more complicated than it should be. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
On Fri, 21 Aug 2020, Bo Berglund via fpc-pascal wrote: What is the advantage of using synaser over serial in a simple non-gui program running in the console in Linux? I have been struggling making LazSerial work in a console app and been adviced to instead use synaser (which is what lazserial is built on). A few months back it seemingly started to work but with some "fixes". Yesterday I needed to quickly make a checkup tool for serial comm and this time (again) I was hit by the appearance of GUI errors. Don't remember how exactly I solved it last time... What I remembered was using widgetset nogui, but it seems impossible to get to such a setting in this simple program. And using 'interfaces' on the line preceding Lazserial was also a fix in the previous app but does not work now. So hence my question: Is there something bad about serial (built-in to fpc) that makes it unsuitable for use? Seems like there are virtually no posts describing solutions using serial... As it is built-in to fpc one would assume it is the preferred way, but for some reason it looks like it is not... Why do you think so ? Why not take it one step at a time ? Write a small console applocation that does what you want (some simple test cases) with the serial unit. You can do the same with synaser and compare your 2 solutions. Then, once satisfied, integrate it in your final solution. That can be GUI program if you need that, but does not have to be so. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Using built-in serial instead of synaser and the like for Linux console app?
What is the advantage of using synaser over serial in a simple non-gui program running in the console in Linux? I have been struggling making LazSerial work in a console app and been adviced to instead use synaser (which is what lazserial is built on). A few months back it seemingly started to work but with some "fixes". Yesterday I needed to quickly make a checkup tool for serial comm and this time (again) I was hit by the appearance of GUI errors. Don't remember how exactly I solved it last time... What I remembered was using widgetset nogui, but it seems impossible to get to such a setting in this simple program. And using 'interfaces' on the line preceding Lazserial was also a fix in the previous app but does not work now. So hence my question: Is there something bad about serial (built-in to fpc) that makes it unsuitable for use? Seems like there are virtually no posts describing solutions using serial... As it is built-in to fpc one would assume it is the preferred way, but for some reason it looks like it is not... (I am using fpc 3.0.4 + Lazarus 2.0.8 on a RaspberryPi (3 and 4)) -- Bo Berglund Developer in Sweden ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal