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
