重叠I / O操作期间的串行端口和处理错误

时间:2009-08-22 14:48:50

标签: delphi serial-port overlapped-io

我最近一直在进行串口通信,所以我准备了一个类,它是所有那些负责读,写等的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)调用会不会永远阻塞当前线程的危险吗?

如果您告诉我上述陈述是否属实,请将其评论,我将不胜感激。

非常感谢你。

1 个答案:

答案 0 :(得分:1)

出于好奇:为什么不使用现有的串行组件?

我使用TurboPower Async接收GPS消息,但还有很多其他免费提供:http://www.efg2.com/Lab/Library/Delphi/IO/PortIO.htm

其中大多数允许您在更高级别进行串行通信,为您抽象出所有较低级别的IO和线程内容。

这样你只需要编写一个onreceive处理程序来接收,并调用send()来发送内容。