[fpc-pascal] Reading Serial Hex Data
Bo Berglund
bo.berglund at gmail.com
Mon Dec 28 13:16:48 CET 2020
On Sun, 27 Dec 2020 18:20:32 -0500, James Richters via fpc-pascal
<fpc-pascal at lists.freepascal.org> wrote:
>>On Sun, 27 Dec 2020 10:47:59 -0500, James Richters via fpc-pascal <fpc-pascal at lists.freepascal.org> wrote:
>>
>>>I'm trying to figure out how to read a packet of HEX Bytes of an
>>>unknown length that have no specific termination character over a
>>>serial port as efficiently as practical.
>>
>>What exactly do you mean by HEX Bytes?
>>Hex transfers using two characters for each byte? like 1F A4 etc?
>
>What I meant by 'Hex Data' is that I am reading data in the form of bytes but they do not represent ASCII characters.
>So if I read a $0D, it's just a byte $0D, it doesn't represent a carriage return. There is no specific code for end of line,
>the last two bytes are a checksum, but I won't know they are the last ones until I'm done reading.
>I'm reading all the data available, then analyzing it.
>
This is NOT wahat is generally meant by hex data, hex data means bytes
are encoded using the ASCII characters 0..9, A..F thus expanding data
size by x2 while making it possible to send over channels that use
control characters to handle transfer details such as line feeds,
start of text and end of text etc.
What you have is straight binary data....
>>
>>Is your program a console or GUI program?
>
>This is a console application.
I suspected as much. Many of the serial components available are
geared towards GUI apps and so for instance LazSerial links in stuff
like Forms and menus and the like, which causes exceptrions when
running in a straight GUI-less environment like a Linux server.
So I created a class named fpserial where I packaged the functions I
needed and used the built-in Serial unit as the basic execution
handler.
This class uses an event model to supply incoming data, which are
received inside a thread and supplied via a synchronized call to the
event function in the main thread of the program.
Being a console program it has a loop which includes CheckSynchronize
to handle this.
After I did that I have had no problems talking to external hardware
sending and receiving data in binary streams.
But there is a "protocol" for the transfers implemented to allow some
control. It looks something like this:
<length><messageID><message><checksum>
Where length is a 4-byte integer containing the length of the transfer
body and checksum is a 16 bit sum over all of the bytes inside the
body (excluding the checksum).
The messages are sent following a handshake between the two sides.
My thread code looks like this:
{ TComPortReadThread }
TComPortReadThread=class(TThread)
private
FBuffer: TBytes;
FReadPacketSize: integer;
FReadTimeout: integer;
public
MustDie: boolean;
Owner: TFpSerialPort;
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;
implementation
{ TComPortReadThread }
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],
FReadPacketSize, FReadTimeout); //Read FReadPacketSize bytes with
timeout of FReadTimeout ms
if cnt > 0 then
begin
SetLength(FBuffer, cnt); //Reduce size to fit received data
Synchronize(CallEvent); //Supply received data in FBuffer to
caller
SetLength(FBuffer, BUFFERSIZE); //Reset buffer size to 8192
bytes.
end;
end;
finally
Terminate;
end;
end;
HTH
--
Bo Berglund
Developer in Sweden
More information about the fpc-pascal
mailing list