应用范围的串口利用率

Application wide serial port utilisation

我正在用 C# 开发 WPF 应用程序并与串行设备通信。目前在我的应用程序的主要 window 中,我正在显示一些我通过定期从串行设备读取线路获得的信息。

有时我需要不断地从串口设备接收数据并将其保存到文件中。我停止了其他使用串行端口的方法(比如定期读取行以显示在主 window 上的方法),这样记录过程就不会受到干扰。跨应用程序管理对串行端口的访问可能很麻烦,因此 "System.UnauthorizedAccessException" 并不少见。

在使用串行设备的应用程序中的每个方法或window中,我定义了一个新的串行端口,打开它,读取行,然后关闭并处理它。我已经读到,在应用程序启动时打开串行端口并在应用程序关闭时关闭它是一种很好的做法,我可以理解为什么这对我要使用此应用程序的地方有帮助。不过我有一些问题:

您应该创建一个单独的 class 来管理 SerialPort 连接。它应该有自己的线程从串行端口读取。然后它可以将它读取的信息分发到应用程序中的其他位置。一种好的方法是使用 Rx。从此 class 创建一个单例并将其注入应用程序中需要它的任何其他地方。

使用Rx,您可以根据需要多次订阅来自串口的消息。

  1. 创建一个class来管理串口:

    public class SerialPortManager
    {
      private SerialPort;
      private string comPort;
      Subject<string> messageBus = new Subject<string>();
      public IObservable<string> MessageBus => messageBus;
      private CancellationTokenSource cts = new CancellationTokenSource();
    
      public SerialPortManager(string comPort)
      {
         this.comport = comport;
      }
    
      public void Start()
      {
          ThreadStart ts = new ThreadStart(SerialDeviceThread);
          Thread t = new Thread(ts);
          t.IsBackground = true;
          t.Name = this.Name;
          t.Start();
      }
    
      private void SerialDeviceThread()
      {
          this.serialPort = new SerialPort(this.comPort, ...);
          while (true)
          {
              string line = this.serialPort.ReadLine();
              this.messageBus.OnNext(line);
          }
       }
    }
    
  2. 在某处创建此 class 的单例:

    public static Lazy<SerialPortManager> SerialPortManager = 
      new Lazy<SerialPortManager>(x => {
            var sm = new SerialPortManager("COM2"); 
            sm.Start(); 
            return sm; 
       });
    

和其他地方

SerialPortManager.Value.MessageBus.Subscribe( ...)

[这仍然大大简化了,我会在串行端口周围有逻辑来捕获故障并在断开连接时重新创建端口。我还会使用依赖注入容器(例如 Autofac)而不是静态值。]

听起来您需要的是一个管理串行端口访问的对象。该对象将设置一次端口对象并启动一个新线程,该线程将从串行端口连续读取行,并在读取该行时触发一个事件。然后,当其他应用程序对象希望收到来自串行端口的数据通知时,它们会将委托附加到该事件。这样,串口的数据就会一直广播给感兴趣的人。根据您的 UI,您必须在 Dispatcher(对于 WPF)或 Windows 表单对象(对于 Windows 表单)上使用 Invoke() 方法来确保事件是从 UI 线程触发,因此它可以正确调用 UI 方法。