如何同步串口操作?
How to synchronize SerialPort operations?
我有一个通过串行端口与微控制器通信的应用程序。我想在后台工作程序中定期检查控制器的状态,并允许用户通过发送命令和接收响应异步地(通过用户界面)与控制器交互。
UI 和 Background Worker 使用 SerialCommunication static class:
static class SerialCommunication
{
static SerialPort serialPort;
static int readWriteTimeout = 1000; // [ms]
static int waitForTransmissionTimeout = 2; // [s]
static string rxData = "", endOfString = "" + char.MinValue;
static bool WaitingForSerialData = false; // Set in SerialWrite(), cleared in SerialRead()
[...]
public static string SerialRead()
{
try
{
rxData = serialPort.ReadTo(endOfString);
}
catch (TimeoutException)
{
WaitingForSerialData = false;
throw new Exception(Properties.Resources.serial_read_timeout);
}
WaitingForSerialData = false;
return rxData;
}
public static void SerialWrite(string text)
{
DateTime start = DateTime.Now;
while (WaitingForSerialData) // Avoids the situation in which a command executed on a thread receives the response for the command executed from a different thread
{
if (!WaitingForSerialData)
{
try
{
WaitingForSerialData = true; // All commands wait for confirmation/data, so it is normal to set this boolean value for every serial transmission
serialPort.Write(text);
}
catch (TimeoutException)
{
throw new Exception(Properties.Resources.serial_write_timeout);
}
}
else
{
System.Threading.Thread.Sleep(100);
if ((DateTime.Now - start).Seconds >= waitForTransmissionTimeout)
{
throw new Exception("Timeout");
}
}
}
}
}
串行端口在应用程序启动时初始化。 SerialWrite
和 SerialRead
在 UI 或 Background Worker 中连续调用。
我想避免一个命令接收来自在不同线程中执行的另一个命令的响应的情况。目前,我已经在 SerialWrite 中实现了在发送命令之前等待接收命令(以便 SerialRead 完成),但恐怕这会阻塞 UI(最多 waitForTransmissionTimeout
秒),如果从那里执行 SerialWrite。
那么同步串口操作的最佳方式是什么?
我不知道整个情况,但在我看来你可以只使用一个简单的锁来序列化你的写入,然后读取,就像这样:
static class SerialCommunication
{
static SerialPort serialPort;
static string endOfString = "" + char.MinValue;
static readonly object _commandLock = new object();
public static string SendCommand(string text) {
lock (_commandLock) {
SerialWrite(text);
return SerialRead();
}
}
private static string SerialRead() {
try {
return serialPort.ReadTo(endOfString);
}
catch (TimeoutException) {
throw new Exception(Properties.Resources.serial_read_timeout);
}
}
private static void SerialWrite(string text) {
try {
serialPort.Write(text);
}
catch (TimeoutException) {
throw new Exception(Properties.Resources.serial_write_timeout);
}
}
}
我有一个通过串行端口与微控制器通信的应用程序。我想在后台工作程序中定期检查控制器的状态,并允许用户通过发送命令和接收响应异步地(通过用户界面)与控制器交互。
UI 和 Background Worker 使用 SerialCommunication static class:
static class SerialCommunication
{
static SerialPort serialPort;
static int readWriteTimeout = 1000; // [ms]
static int waitForTransmissionTimeout = 2; // [s]
static string rxData = "", endOfString = "" + char.MinValue;
static bool WaitingForSerialData = false; // Set in SerialWrite(), cleared in SerialRead()
[...]
public static string SerialRead()
{
try
{
rxData = serialPort.ReadTo(endOfString);
}
catch (TimeoutException)
{
WaitingForSerialData = false;
throw new Exception(Properties.Resources.serial_read_timeout);
}
WaitingForSerialData = false;
return rxData;
}
public static void SerialWrite(string text)
{
DateTime start = DateTime.Now;
while (WaitingForSerialData) // Avoids the situation in which a command executed on a thread receives the response for the command executed from a different thread
{
if (!WaitingForSerialData)
{
try
{
WaitingForSerialData = true; // All commands wait for confirmation/data, so it is normal to set this boolean value for every serial transmission
serialPort.Write(text);
}
catch (TimeoutException)
{
throw new Exception(Properties.Resources.serial_write_timeout);
}
}
else
{
System.Threading.Thread.Sleep(100);
if ((DateTime.Now - start).Seconds >= waitForTransmissionTimeout)
{
throw new Exception("Timeout");
}
}
}
}
}
串行端口在应用程序启动时初始化。 SerialWrite
和 SerialRead
在 UI 或 Background Worker 中连续调用。
我想避免一个命令接收来自在不同线程中执行的另一个命令的响应的情况。目前,我已经在 SerialWrite 中实现了在发送命令之前等待接收命令(以便 SerialRead 完成),但恐怕这会阻塞 UI(最多 waitForTransmissionTimeout
秒),如果从那里执行 SerialWrite。
那么同步串口操作的最佳方式是什么?
我不知道整个情况,但在我看来你可以只使用一个简单的锁来序列化你的写入,然后读取,就像这样:
static class SerialCommunication
{
static SerialPort serialPort;
static string endOfString = "" + char.MinValue;
static readonly object _commandLock = new object();
public static string SendCommand(string text) {
lock (_commandLock) {
SerialWrite(text);
return SerialRead();
}
}
private static string SerialRead() {
try {
return serialPort.ReadTo(endOfString);
}
catch (TimeoutException) {
throw new Exception(Properties.Resources.serial_read_timeout);
}
}
private static void SerialWrite(string text) {
try {
serialPort.Write(text);
}
catch (TimeoutException) {
throw new Exception(Properties.Resources.serial_write_timeout);
}
}
}