使用this example我创建了两个用于在串行端口上读取设备的类。该设备是一个激光器,我可以使用SYST:STAT?等命令控制(打开/关闭系统/激光,读取统计数据等)。大多数命令会立即发回一个我可以使用_serialPort.ReadLine()读取的响应。
但是,打开系统的命令SYST:STAT ON是大约需要十秒钟的命令之一。这就是激光制造商决定发送一条消息说:系统就绪的好处。我可以使用NewSerialDataRecieved事件异步读取此响应。在这里,我读了这样的每一行:
private void OnDataReceived(object sender, SerialDataEventArgs e)
{
_dataReceived += Encoding.ASCII.GetString(e.Data);
// Loop as long as there's full lines available
while (_dataReceived.Length > 0 && _dataReceived.Contains("\r\n"))
{
int delimiterIndex = _dataReceived.IndexOf("\r\n", StringComparison.Ordinal) + 2;
string line = _dataReceived.Substring(0, delimiterIndex); // Get first line from data
_dataReceived = _dataReceived.Substring(delimiterIndex, _dataReceived.Length - line.Length); // Remove first line from data
line = line.Substring(0, line.Length - 2);
TryParseSystemReadyResponse(line);
TryParseEnteringStandbyModeResponse(line);
TryParseTemperatureResponse(line);
OnResponseReceived?.Invoke(line);
}
}
该方法读取传入的数据,存储它,然后逐行解析数据。这非常适合我的异步,定义明确的响应。这里有一个问题:大多数回复都被格式化为' 0 0'或者' 0 1'。这意味着没有办法像那样解析它们。这就是我将命令发送到串行设备后直接读取它们的原因,如下所示:
public void UpdateLaserState()
{
// Get the selected laser
_serialPortManager.SendCommand("LSR:NSEL?");
int selectedLaser = _serialPortManager.ReadIntegerResponse();
// Do stuff with the laser number
OnSystemStateChange?.Invoke();
}
ReadIntegerResponse是一种执行ReadLine的方法,它会删除前面的' 0'然后将剩余的字符串解析为int。到目前为止,沟通工作和我期望的一样。可以立即读取可以同步的消息,并且可以通过OnDataReceived方法解析异步消息。
这就是问题所在。我需要大约两秒读取激光系统的温度。我的解决方案是创建一个读取温度的线程,如下所示:
public Laser(){
_temperatureThread = new Thread(TemperatureTask);
_temperatureThread.Start();
_temperatureThreadRunning = true;
}
public void Dispose()
{
_temperatureThreadRunning = false;
_temperatureThread.Join();
}
private void TemperatureTask()
{
while (_temperatureThreadRunning)
{
this.UpdateTemperatures();
Thread.Sleep(TemperatureTaskSleep);
}
}
public void UpdateTemperatures()
{
_serialPortManager.SendCommand("SYST:TEMP?");
//string line = _serialPortManager.ReadResponse();
//TryParseTemperatureResponse(line);
}
这会产生问题,因为UpdateTemperatures会在不同的线程上经常发送响应。我通过实现锁解决了很多问题。但是,我的回答经常变得混乱。我认为以下情况正在发生:
Main thread Temperature thread
-----------------------------------------
Sends command |
| Sends command
Reads response |
| Reads response
这意味着线程正在读取每个响应。没有什么好方法可以识别像' 0 0'属于某个命令。
有没有办法防止这种情况发生?
P.S。 _serialPortManager的ReadResponse方法看起来都像这样(解析响应除外):
public string ReadResponse()
{
string response = SafeReadLine();
return StripResponse(response);
}
private string SafeReadLine()
{
lock (_serialPortLock)
{
string response = _serialPort.ReadLine();
return StripResponse(response);
}
}