我正在尝试使用串行通信与定制硬件进行通信。硬件具有内置方法,可以通过命令调用。
要发送命令并读取函数的输出(从硬件),我使用
AutoResetEvent
事件,如下所示:
private string receiveMessage(string command)
{
string rxMessage = "Error";
var mre = new AutoResetEvent(false);
var buffer = new StringBuilder();
serialPort.DataReceived += (s, e) =>
{
buffer.Append(serialPort.ReadExisting());
if (buffer.ToString().IndexOf("\r\n") >= 0)
{
rxMessage = buffer.ToString();
mre.Set();
buffer.Clear();
}
};
var responseTimeout = TimeSpan.FromSeconds(10);
try
{
serialPort.WriteLine(command);
if (!mre.WaitOne(responseTimeout))
{
rxMessage = "Did not receive response";
}
}
catch (TimeoutException)
{
rxMessage = "Write took longer than expected";
}
catch
{
rxMessage = "Failed to write to port";
}
return rxMessage;
}
此方法在第一次调用时就可以完美运行。但是,如果第二次调用,串口超时,该方法返回“未收到响应”。
我是否遗漏了什么或者我错误地创建了
receieveMessage()
方法?
非常感谢。
这很可能是由于未取消注册事件处理程序造成的。因此,当您第二次调用
receiveMessage
时,您将不得不使用不同的事件处理程序。第一个将读取所有数据并设置其自动重置事件。当调用第二个事件处理程序时,没有数据可读取,并且其自动重置事件将超时。
要解决这个问题,您有几种选择。一种是注销事件处理程序。为此,您需要将 lambda 转换为委托对象,即
SerialDataReceivedEventHandler myHandler = (s, e) => {...}
serialPort.DataReceived += myHandler ;
...
serialPort.DataReceived -= myHandler ;
或者将 lambda 替换为 本地函数。
另一种选择是将方法更改为类,这样您只需注册一次 DateReceived 事件。
请注意,我认为你有竞争条件。如果在调用
WaitOne
之前接收到数据,则不会设置该事件,并且您将超时。使用 ManualResetEvent/ManualResetEventSlim 保持信号状态直到显式重置应该可以避免此问题。