我们的C#应用程序通过串口与设备通信。该协议是一种简单的请求/响应,如协议。
在大多数情况下,一切都运行正常,但在某些机器上,我们有时会遇到以下请求响应的超时和陈旧数据。
我编写了一个单线程控制台应用程序,并设法在虚拟机中可靠地重现问题,我将CPU限制在10%左右。该应用程序基本上执行以下操作:
_port = new SerialPort(
"COM1",
115200,
Parity.None,
8,
StopBits.One)
{
RtsEnable = false,
DtrEnable = false,
Handshake = Handshake.None,
ReadTimeout = 5000
WriteTimeout = 5000
};
_port.Open();
_port.DiscardInBuffer();
_port.DiscardOutBuffer();
_readBuffer = new byte[1024];
// Send requests periodically...
while (true)
{
var requestBytes = ...; // Encode the request
_port.Write(requestBytes, 0, requestBytes.Length);
try
{
var responseStream = new List<byte>(1024);
int count = ...; // Calculate number of bytes of the response
int remainingBytesCount = count;
while (numberOfBytesReadTotal < count)
{
int bytesToRead = Math.Min(_readBuffer.Length, remainingBytesCount);
int numberOfBytesRead = _port.Read(_readBuffer, 0, bytesToRead);
if (numberOfBytesRead <= 0)
break;
remainingBytesCount -= numberOfBytesRead;
responseStream.AddRange(_readBuffer.Take(numberOfBytesRead));
}
// Parse the response and if it is valid, dump it. Otherwise throw an exception
var response = ParseResponse(responseStream);
Console.WriteLine(FormatResponse(response));
}
catch (Exception err)
{
Console.WriteLine("ERROR OCCURED: " + err);
Console.WriteLine("Sleep some time, then discard in and out buffers and then proceed");
Thread.Sleep(10000);
_port.DiscardInBuffer();
_port.DiscardOutBuffer();
}
}
在短时间内它成功运行,但是在读取响应的过程中突然间,读取循环内的Read()调用超时并抛出TimeoutException
。
如您所见,应用程序等待10秒钟以确保设备已发送剩余数据。然后我们丢弃串口的输入和输出缓冲区并重新开始。
现在有一个我不理解的非常奇怪的效果:对于下一个请求,读取的数据是尚未从先前请求超时读取的陈旧数据!在我看来,这不应该发生,因为我放弃了进出缓冲区。
为了确保问题不是设备本身,我们的工程师之一将数字示波器放在设备前面并记录数据流量:设备快速响应请求并在一秒钟内将所有响应数据发送到电脑所以应该没有超时。第二,它不会发送错误的数据作为对超时请求之后的请求的响应。
这个问题似乎与CPU的速度有关。当我以全速运行虚拟机时,测试应用程序成功运行几分钟,直到我停止它。我越低CPU速度,越快出现错误。
设备行为正常,小型控制台应用程序似乎是正确的。看起来串口驱动程序有问题。
有没有人可以尝试一些提示?