我正在编写一个与一台测试设备交谈的界面。设备通过串行端口进行通信,并对发送的每个命令以已知的字节数进行响应。
我目前的结构是:
但是,当我使用SerialPort.Read(byte [],int32,int32)时,该函数没有阻塞。因此,例如,如果我调用MySerialPort.Read(byteBuffer, 0, bytesExpected);
,则函数返回的值小于指定的bytesExpected
。这是我的代码:
public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
MySerialPort.ReadTimeout = timeOut;
int bytesRead = MySerialPort.Read(responseBytes, 0, bytesExpected);
return bytesRead == bytesExpected;
}
我称这种方法是这样的:
byte[] responseBytes = new byte[13];
if (Connection.ReadData(responseBytes, 13, 5000))
ProduceError();
我的问题是,我似乎无法像我所说的那样读取完整的13个字节。如果我在Thread.Sleep(1000)
之前放置SerialPort.Read(...)
,一切正常。
如何强制Read
方法阻止,直到超出timeOut或读取指定的字节数?
答案 0 :(得分:11)
这是预期的;大多数IO API允许您指定上部绑定仅 - 它们只需返回至少一个字节,除非它是EOF,在这种情况下它们可以返回非正值。为了补偿,你循环:
public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
MySerialPort.ReadTimeout = timeOut;
int offset = 0, bytesRead;
while(bytesExpected > 0 &&
(bytesRead = MySerialPort.Read(responseBytes, offset, bytesExpected)) > 0)
{
offset += bytesRead;
bytesExpected -= bytesRead;
}
return bytesExpected == 0;
}
唯一的问题是,您可能需要通过使用Stopwatch
或类似内容来减少每次迭代的超时,以查看已经过了多长时间。
请注意,我还删除了ref
上的responseBytes
- 您不需要它(您不会重新分配该值)。
答案 1 :(得分:1)
尝试将超时更改为InfiniteTimeout
。
答案 2 :(得分:0)
如果在SerialPort.ReadTimeout之前没有可用的字节,则预计SerialPort.Read会抛出TimeoutException。 因此,此方法准确读取所需的数字或字节,或引发异常:
public byte[] ReadBytes(int byteCount) {
try
{
int totBytesRead = 0;
byte[] rxBytes = new byte[byteCount];
while (totBytesRead < byteCount) {
int bytesRead = comPort.Read(rxBytes, totBytesRead, byteCount - totBytesRead);
totBytesRead += bytesRead;
}
return rxBytes;
}
catch (Exception ex){
throw new MySerialComPortException("SerialComPort.ReadBytes error", ex);
}
}