[Lazarus] Advice needed for serial comm with Lazarus
Bo Berglund
bo.berglund at gmail.com
Sat Nov 6 00:49:59 CET 2010
I have already been adviced to use the SdpoSerial component for my
serial comm project. The project is a platform-independent rewrite of
a data acquisition instrument communications program.
It was originally written in Delphi7 using a Windows based serial
communications component (not AsyncPro).
So now I have to refrain from Windows specific stuff...
Therefore I am looking for advice on platform-independent programming
using the SdpoSerial component..
The protocol used is basically as follows:
1) There are 1-byte commands to switch the instrument into and out
from two remote modes. All of these 4 commands work the same way:
- The host sends a control byte
- Then it waits with timeout for the response (ACK or NAK)
- The timeout is 2s.
2) Data transfer from the instrument is a bit different:
- The host sends the command, which is identified by a leading command
byte followed by command dependent parameters, for example the start
address and length for reading a memory block.
- Then the host waits for the response with timeout.
- In this case the response will be longer, it is always a chunk of
data starting with the length of the data to follow, then the actual
data and finally a checksum.
In the Delphi implementation I have done as follows:
1) There is a function to send the simple command and wait for
response, which purges the buffers, then sends the command and then
enters a loop approximately like below (there is also an OnRxData
event for the serial component where incoming data are written into a
string buffer):
var
T1: Cardinal; //for timeout
begin
Result := false;
T1 := GetTickCount;
FComm.ZapRxqueue;
FRxBuf := '';
FComm.SendChar(cmd);
while Length(FRxBuf) = 0 do
begin
Sleep(2);
if GetTickCount - T1 > FTimeout then break;
end;
if Length(FRxBuf) = 0 then exit;
Result := FRxBuf[1] = ACK;
end;
Here I have a few possible compatibility problems:
- GetTickCount is used to handle the timeout. Windows specific?
- Sleep(2) is used to yield in the loop so serial data can arrive.
How should I do here in order to get the code portable?
2) In the case of the data transfer I need to wait for the first 4
bytes of the response to know how big the incoming packet will be.
So this is done in the same way as above, only here I have to wait
(with timeout) until the buffer length becomes >= 4 at which time I
can calculate the total number of bytes to expect.
Then I will wait in a loop similar to the one above until the buffer
string length becomes this plus the checksum.
In the Delphi implementation I have an incrementing progress bar
inside the loop (whenever 512 new bytes have arrived it is
incremented) plus a check for a user break condition on a Cancel
button. There is also a timeout check for the case when characters
stop arriving before all are collected.
What is the recommended way to handle such situations? The data
transfer may take several minutes for large data chunks and I have to
keep the application responsive while giving feedback to the user
about the progress...
I am also thinking of replacing the string buffer with a TMemoryStream
object.
Bo Berglund
More information about the Lazarus
mailing list