Comport readstr

穿精又带淫゛_ 提交于 2019-12-08 06:54:41

问题


I'm trying to reading a simple string from host on Serial line RS232. The parameters of receive - transmission are the same for both:

Baudrate: 9600;
Data: 8bit;
Parity: None;
Stop: 1bit;
Flow Control: None;

I've tried to send this string:

!A243B324C213D300#

I use '!' and '#' as header and finish to be sure the string will be received at all. The problem is that I can receive the string until the 15th character (3).

I know this because if I use this code:

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
begin
 ComPort1.ReadStr(Str, Count);
 memo1.Lines.Add(str);
end;

I will see


!A243B324C213D3

00#


I've tried to extend the buffer of the comport, without results.

So why I can't receive the complete string in one shot?

I found this library here and it works fine until now:

http://sourceforge.net/projects/comport/


回答1:


With TComPort component comes another one: TComDataPacket. Simply connect this to TComPort, setup StartString and StopString properties and use event onPacket to get complete data.

example:

...
    ComDataPacket1.Comport := Comport1;
    ComDataPacket1.StartString := '!';
    ComDataPacket1.StopString := '#';
    ComDataPacket1.onPacket := ComDataPacket1Packet;
...

//this is real code from one of my applications where I use it for barcode reader service
procedure TDM.ComDataPacket1Packet(Sender: TObject; const Str: string);
begin
     BarCodeReader.Barcode := Str;  
end;



回答2:


You cannot rely on receiving complete messages in any communications at that low level of communication. Also you cannot rely on receiving only one message at a time.

You must implement something, that will guarantee to notify only on complete messages.

To do so you have to store the incoming data until you receive the complete message (header and finish flags).

Here is a small console app with a TMessageBuffer class, that handles the incoming data and complete messages

program so_22436319;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  SysUtils;

type
  TMessageBuffer = class
  private
    FBuffer : string;
    FMsgPart : Boolean;
    procedure DoHandleMessage( const CompleteMessage : string );
  public
    procedure AddData( const Data : string );
  end;

procedure Test;
var
  LMsgBuffer : TMessageBuffer;
begin
  LMsgBuffer := TMessageBuffer.Create;
  try
    // receive complete message
    LMsgBuffer.AddData( '!A243B324C213D300#' );
    // receive 2 complete message in one go
    LMsgBuffer.AddData( '!A243B324C213D300#!A243B324C213D300#' );
    // receive parts of the message
    LMsgBuffer.AddData( '!A243B324' );
    LMsgBuffer.AddData( 'C213D300#!A243' );
    LMsgBuffer.AddData( 'B324C213D300#!A' );
    LMsgBuffer.AddData( '243B324C2' );
    LMsgBuffer.AddData( '13D300#' );

  finally
    LMsgBuffer.Free;
  end;
end;

  { TMessageBuffer }

procedure TMessageBuffer.AddData( const Data : string );
var
  LIdx : Integer;
  LChar : Char;
begin
  for LIdx := 1 to Length( Data ) do
  begin
    LChar := Data[LIdx];
    if FMsgPart then
      if LChar = '#' then
      begin
        DoHandleMessage( FBuffer );
        FMsgPart := False;
        FBuffer := '';
      end
      else
      begin
        FBuffer := FBuffer + LChar
      end
    else if LChar = '!' then
    begin
      FMsgPart := True;
    end;
  end;
end;

procedure TMessageBuffer.DoHandleMessage( const CompleteMessage : string );
begin
  Writeln( 'MSG: ', CompleteMessage );
end;

begin
  try
    Test;
  except
    on E : Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;
  ReadLn;
end.

The generated output is

MSG: A243B324C213D300
MSG: A243B324C213D300
MSG: A243B324C213D300
MSG: A243B324C213D300
MSG: A243B324C213D300
MSG: A243B324C213D300

The class removes the header and finish char, because this is part of the transportation protocol and therefore not needed any more. But you can still add it if you like.



来源:https://stackoverflow.com/questions/22436319/comport-readstr

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!