我正在使用.NET 4.0开发一个项目。我有一个通过串口连接的设备,我发送命令,然后等待响应。一旦收到响应,我将检查响应以确保它是有效的,然后发送下一个命令。
主要问题是我发送的命令响应时间差异很大。一个命令的响应可能需要30ms或30秒。因此我实施了一个TimerCallback来检查串口的每500ms的响应。我已经发布了下面的代码以及我得到的输出。
// From different class
private string SendCommandAwaitResponse(string command)
{
// Set timeout to 30 seconds.
this.port.ReadTimeout = 30000;
// Clears existing
this.port.ReadExisting();
this.port.Write(command);
var autoEvent = new AutoResetEvent(false);
var responseTimer = new ResponseTimer(port, command);
var timer = new Timer(responseTimer.GetResponse, autoEvent, 0, 500);
autoEvent.WaitOne();
Trace.WriteLine(string.Format("AutoEvent Set: {0}", command));
timer.Dispose();
return responseTimer.Response;
}
public class ResponseTimer
{
private ISerialPort serialPort;
private string command;
private bool isAttemptingRead;
public string Response
{
get { return this.response; }
set
{
if (this.response == value)
return;
this.response = value;
}
}
private string response;
public ResponseTimer(ISerialPort port, string command)
{
Trace.WriteLine("Constructor Created");
this.isAttemptingRead = false;
this.serialPort = port;
this.command = command;
Response= string.Empty;
}
public void GetResponse(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
try
{
if (!isAttemptingRead)
{
Trace.WriteLine("Initiating ReadLine");
Response= serialPort.ReadLine();
isAttemptingRead = true;
}
Trace.WriteLine("Try: " + Response);
}
catch (TimeoutException ex)
{
Trace.WriteLine(String.Format("EX: TIMED OUT: Response {0}", Response));
autoEvent.Set();
}
Trace.WriteLine(String.Format("CURRENT Response {0}", Response));
if (Response == command)
{
Trace.WriteLine(string.Format("COMMAND: {0}", command));
Trace.WriteLine(string.Format("Clearing Buffer: {0}", Response));
Response= string.Empty;
isAttemptingRead = false;
}
else if (!string.IsNullOrEmpty(Response))
{
Trace.WriteLine(String.Format("Got Response - {0}", Response));
autoEvent.Set();
}
else if (string.IsNullOrEmpty(Response))
Trace.WriteLine("Empty or Null read");
}
}
代码适用于较小的响应时间(30ms),但当它到达响应时间为30秒的命令时,我得到以下输出(主要是)。
的WriteLine(#XSFCD)
然后我通常只是结束程序。我是否错过了使用TimerCallback方法的东西?
答案 0 :(得分:1)
从MSDN页面:
将等到它在串口上看到行尾字符或者直到ReadTimeout已经过去。
...
默认情况下,ReadLine方法将阻塞,直到收到一行。如果不希望出现这种情况,请将ReadTimeout属性设置为任何非零值,以强制ReadLine方法在端口上没有行时抛出TimeoutException。
提供以指定的时间间隔在线程池线程上执行方法的机制。
因此每个计时器回调可能在一个单独的线程上,每个readline()调用暂停当前线程,直到它看到行尾字符。无论发生了什么,您的计时器每500毫秒触发一次。所以第一个调用readline()并在那里等待行尾字符。它没有看到它,所以它一直在等待。 500ms后,另一个线程完全相同。 500毫秒后,同样的事情发生,等等。所以你堆叠所有这些readline()调用等待readline()完成。最终你厌倦了等待并杀死程序。您可以使用readExisting()来读取当前缓冲区,而不是readLine(),但您必须找到行尾字符的位置。或者你可以完全摆脱计时器并使用serialport事件(例如DataReceived)告诉你何时获得了一些数据。