使用 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 在端口 COM6
和 COM7
之间创建桥接。
我正在端口 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;
我正在尝试在 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 在端口 COM6
和 COM7
之间创建桥接。
我正在端口 COM6
问题是,即使我用 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;