我最近一直在进行串口通信,所以我准备了一个类,它是所有那些负责读,写等的Windows API函数的简单接口。这个类中的所有I / O操作都是异步处理的。
在我回答我的问题之前,让我告诉你我如何从串口写入和读取数据(这只是读取功能,因为写入的结构完全相同,所以两者都没有意义他们)。
function TSerialPort.Read(var pBuffer; const lBufferSize: Cardinal): Cardinal;
var
lOverlapped: OVERLAPPED;
lLastError: Cardinal;
lEvent: TEvent;
begin
lEvent := TEvent.Create(nil, True, False, '');
try
FillChar(lOverlapped, SizeOf(lOverlapped), 0);
lOverlapped.hEvent := lEvent.Handle;
if not ReadFile(FSerialPortHandle, pBuffer, lBufferSize, Result, @lOverlapped) then
begin
lLastError := GetLastError;
if (lLastError <> ERROR_IO_PENDING) and (lLastError <> ERROR_SUCCESS) then
raise Exception.Create(SysErrorMessage(lLastError));
case lEvent.WaitFor(INFINITE) of
wrSignaled:
if not GetOverlappedResult(FSerialPortHandle, lOverlapped, Result, False) then
raise Exception.Create(SysErrorMessage(GetLastError));
wrError:
begin
lLastError := lEvent.LastError;
//this is a call to Windows.CancelIo(FSerialPortHandle);
if Self.CancelIO() then
lEvent.WaitFor(INFINITE);
raise Exception.Create(SysErrorMessage(lLastError));
end;
end;
end;
finally
FreeAndNil(lEvent);
end;
end;
在你问我为什么打开串口进行重叠操作时,这个函数等待读操作完成,这是我的解释 - 只有在打开串口这种方式时才能指定WaitCommEvent()方法等待事件的时间。如果我打开非重叠操作的端口,WaitCommEvent()将阻塞,直到串口上出现一个事件,这不会总是发生,导致调用线程永远阻塞。
然而,让我们专注于上面的Read()函数。
1)首先,我等待没有时间限制来设置事件。由于某种原因,当前线程是否有可能永远阻塞?我不知道我是否可以100%确定事件迟早会被执行异步读取操作的线程设置。我知道当串口的读取超时都设置为零时,读取操作将不会完成,直到读取给定的字节数,但这是我所知道的行为。我的问题涉及导致事件永远不会被设置并且WaitFor()方法永远等待的意外情况 - 是否可能发生?
2)WaitFor()可能会返回wrError,通知在等待操作期间发生了一些错误(但这根本没有与重叠的读取操作相关联,对吗?)。因此,我认为我不应再等待读取操作完成,因为事件句柄可能不再可用,对吧? 所以我调用CancelIO()方法来取消读取操作,等待线程设置事件异步执行取消读取,然后才引发异常。我等待该线程取消读取,因为如果我立即离开了我的Read()方法(没有取消I / O),我会使该线程将其数据(重叠的记录数据)写入局部变量不再有效,对吧? 另一方面,由于在引发异常之前WaitFor(INFINITE)调用会不会永远阻塞当前线程的危险吗?
如果您告诉我上述陈述是否属实,请将其评论,我将不胜感激。
非常感谢你。
答案 0 :(得分:1)
出于好奇:为什么不使用现有的串行组件?
我使用TurboPower Async接收GPS消息,但还有很多其他免费提供:http://www.efg2.com/Lab/Library/Delphi/IO/PortIO.htm
其中大多数允许您在更高级别进行串行通信,为您抽象出所有较低级别的IO和线程内容。
这样你只需要编写一个onreceive
处理程序来接收,并调用send()
来发送内容。