监测串口变化

监测串口变化

软件与串口设备进行通信时,需要监测串口的状态,以便更新串口设备的连接状态。

遗产代码中采用后台线程定时轮训进行监测。为了能够及时轮训,使用较小的轮训间隔。

轮训有一个冲突:

轮训间隔小,造成资源浪费;轮训间隔大,轮训不及时。

为避免一个线程的资源浪费改成事件监测。

/// <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;
        }
    }
}    

打赏