软件与串口设备进行通信时,需要监测串口的状态,以便更新串口设备的连接状态。
遗产代码中采用后台线程定时轮训进行监测。为了能够及时轮训,使用较小的轮训间隔。
轮训有一个冲突:
轮训间隔小,造成资源浪费;轮训间隔大,轮训不及时。
为避免一个线程的资源浪费改成事件监测。
/// <summary>
/// Monitor serialport changes
/// 尹永贤
/// yinyongxian@qq.com
/// 2019-1-28 15:35:06
/// </summary>
public static class SerialPortService
{
static SerialPortService()
{
serialPortNames = GetSerialPortNames();
MonitorDeviceChanges();
}
private static string[] serialPortNames;
private static ManagementEventWatcher arrival;
private static ManagementEventWatcher removal;
public static IEnumerable<string> SerialPortNames
{
get { return serialPortNames; }
}
public static event EventHandler<SerialPortsChangedEventArgs> SerialPortsChanged;
private static void RaiseSerialPortsChanged(EventType eventType)
{
var handler = SerialPortsChanged;
if (handler != null)
{
var eventArgs = new SerialPortsChangedEventArgs(eventType, serialPortNames);
handler(null, eventArgs);
}
}
private static void MonitorDeviceChanges()
{
try
{
var deviceArrivalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var deviceRemovalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
arrival = new ManagementEventWatcher(deviceArrivalQuery);
removal = new ManagementEventWatcher(deviceRemovalQuery);
arrival.EventArrived += (sender, e) => OnPortsChanged(EventType.Insertion);
removal.EventArrived += (sender, e) => OnPortsChanged(EventType.Removal);
arrival.Start();
removal.Start();
}
catch (Exception)
{
// ignored
}
}
private static void OnPortsChanged(EventType eventType)
{
lock (serialPortNames)
{
var availableSerialPorts = GetSerialPortNames();
if (!serialPortNames.SequenceEqual(availableSerialPorts))
{
serialPortNames = availableSerialPorts;
RaiseSerialPortsChanged(eventType);
}
}
}
private static string[] GetSerialPortNames()
{
try
{
var currentPortNames = SerialPort.GetPortNames();
return currentPortNames;
}
catch (Exception)
{
return Enumerable.Empty<string>().ToArray();
}
}
}
public enum EventType
{
Insertion,
Removal
}
public class SerialPortsChangedEventArgs : EventArgs
{
private readonly EventType eventType;
private readonly string[] serialPortNames;
public SerialPortsChangedEventArgs(EventType eventType, params string[] serialPortNames)
{
this.eventType = eventType;
this.serialPortNames = serialPortNames;
}
public IEnumerable<string> SerialPortNames
{
get
{
return serialPortNames;
}
}
public EventType EventType
{
get
{
return eventType;
}
}
}