使用 CPort 进行线程化

Threading with CPort

我正在尝试在 delphi 中编写一个简单的 CPort 应用程序。

我想让它监听一个端口,收到消息后,它会等待 4 秒,然后发送一个字符串作为响应。

unit Tests.Mocks.Refractometer;

interface

uses
  CPort,
  Classes
  ;

type
  TRefractometerMock = class
    strict private
      MockRunThread : TThread;
      ComPort : TComPort;
      ComDataPacket: TComDataPacket;
    public
      procedure Open;
      procedure HandlePacket(Sender : TObject; const Str : String);

      constructor Create; overload;
      constructor Create(BaudRate : TBaudRate; Port : String); overload;
      destructor Destroy; override;
  end;

implementation

uses
  SysUtils,
  StrUtils
  ;

procedure TRefractometerMock.HandlePacket(Sender : TObject; const Str : String);
begin
    MockRunThread.Start;    
end;

procedure TRefractometerMock.Open;
begin
    ComPort.Open;
end;

constructor TRefractometerMock.Create(BaudRate : TBaudRate; Port : String);
begin
    Self.Create;
    Self.ComPort.Port := Port;
    Self.ComPort.BaudRate := BaudRate;
end;

constructor TRefractometerMock.Create;
begin
    inherited;
    ComPort := TComPort.Create(nil);
    ComDataPacket := TComDataPacket.Create(nil);

    ComDataPacket.ComPort := ComPort;
    ComDataPacket.OnPacket := HandlePacket;

    MockRunThread := TThread.CreateAnonymousThread
    (
        procedure
        begin
            Sleep(4000);
            Self.ComPort.WriteStr('nD=1.33308;');
        end
    );
end;

destructor TRefractometerMock.Destroy;
begin
    if Assigned(Self.ComPort)  then FreeAndNil(Self.ComPort);
    if Assigned(ComDataPacket) then FreeAndNil(ComDataPacket);
    if Assigned(MockRunThread) then FreeAndNil(MockRunThread);

    inherited;
end;

end.

使用这个单元我可以使用下面的代码来

开始收听

RefractometerMock := TRefractometerMock.Create(TBaudRate.br9600, 'COM7');
try
    RefractometerMock.Open;

    Sleep(8000);

finally
    FreeAndNil(RefractometerMock);
end;

另请注意,我正在使用 com0com 在端口 COM6COM7 之间创建桥接。

我正在端口 COM6

上发送 putty 消息

问题是,即使我用 putty 发送了一条消息,HandlePacket 方法也不会被调用,直到 TRefractometerMock 对象被释放。

首先

然后

然后

终于

我什至不确定这是怎么可能的,因为我认为这个对象已经被销毁了。

我没有看到 ComDataPacket 的任何设置。来自帮助:Packet ends when one of stop conditions occurs。您是否定义了这些停止条件?
您是否检查过在简单的独立应用程序中使用 ComDataPacket 接收数据,没有中间件 class?

顺便说一句,似乎TTimer可以完成这项工作,这里不需要线程。

您正在阻塞主线程 Sleep(8000)。这意味着 com 端口驱动程序无法调用 HandlePacket 方法。

当睡眠结束时,再处理任何事情都来不及了,因为一切都被释放了。

由于您正在处理匿名线程的生命周期,因此应将 FreeOnTerminate 属性 设置为 false。并在匿名线程后释放 com 端口。

使用计时器代替 Sleep() 调用。

由于 Brian Frost 想要代码,所以它太大而无法放入评论中。

创建一个简单的表单

type
  TFrmMockRefrac = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    RefractometerMock : TRefractometerMock;
    { Public declarations }
  end;

var
  FrmMockRefrac: TFrmMockRefrac;

在没有 Sleep 函数的情况下处理创建和销毁

procedure TFrmMockRefrac.FormCreate(Sender: TObject);
begin
    RefractometerMock := TRefractometerMock.Create(TBaudRate.br9600, 'COM7');
    RefractometerMock.Open;
end;

procedure TFrmMockRefrac.FormDestroy(Sender: TObject);
begin
    FreeAndNil(RefractometerMock);
end;