SerialPort.DataReceived重复订阅/取消订阅

时间:2009-08-18 14:42:02

标签: c# serial-port

我正在使用串行端口与远程诊断设备进行通信。

来自远程设备的响应长度因命令而异,但提前知道。所以,目前我发送命令并等待接收所需的响应字节数。

每当我不主动请求数据时,我都会订阅'SerialPort.DataReceived'事件。此事件的处理程序只是将任何“未经请求的”接收数据转储到日志中(通常仅在远程设备意外重启时才会收到未经请求的数据等)。

在某些情况下,我想以大约60Hz的速率发送命令。

我的问题是,每当我调用'SendCommand'方法主动请求数据时,是否最好取消订阅/订阅'SerialPort.DataReceived'事件,或者我应该单独留下事件订阅并只切换布尔值'TransferInProgress '标记DataReceived处理程序在我正在积极征求它时可以用来忽略传入的数据吗?

以下是当前的实施:

public virtual bool SendCommand(byte[] command, ref byte[] response) {

    try {
        TransferInProgress = true;
        OnTransferStarted();

        // temporarily unsubscribe since we're actively soliciting data
        _port.DataReceived -=
            new SerialDataReceivedEventHandler(SerialPort_DataReceived);

        _port.DiscardInBuffer();
        _port.Write(command, 0, command.Length);
        OnCommandSent(command);

        // read the requested number of response bytes
        int responseBytesRead = 0;

        while (responseBytesRead < response.Length) {
            responseBytesRead +=
                _port.Read(response, responseBytesRead, (response.Length - responseBytesRead));
        }

        OnCommandResponseReceived(response);
        return true;
    }
    catch (Exception ex) {
        OnCommandSendFailed(ex.Message);
        return false;
    }
    finally {
        _port.DataReceived +=
            new SerialDataReceivedEventHandler(SerialPort_DataReceived);
        OnTransferComplete();
        TransferInProgress = false;
    }
}

-Trevor

3 个答案:

答案 0 :(得分:0)

我的意见是,如果我理解正确,只需在DataReceived处理程序中处理所有接收数据,或者您有另外一个选项。

如果在实际请求之间收到的数据不多,您可以在发送请求之前读取缓冲区并进行记录。串行驱动程序接收缓冲区可能足以存储少量数据。然后发送请求并仅读入响应。这可能是更简单的方法和更简单的代码。

答案 1 :(得分:0)

我通常切换一个布尔值。通过订阅/取消订阅,您可能会多次订阅同一事件。例如,如果OnTransferStarted()引发异常,您的代码将在DataReceived事件中订阅两次。

答案 2 :(得分:0)

您是否考虑过在一个地方处理所有数据接收?您可以将发送的命令视为火灾并忘记,解析收到的响应数据。如果响应没有标识头,并且您知道如何解析它们的唯一方法是知道您发送的命令和响应的长度,那么您可以跟踪队列中发送的命令。可行的方法是,在您的数据接收处理程序中,您将检查您正在等待响应的命令队列,然后像现在一样解析收到的数据。

长话短说,我建议在一个地方处理所有传入的数据。