c# - Windows 通用应用程序串行端口无法打开,SerialDevice.FromIdAsync 始终为空

标签 c# windows serial-port win-universal-app

我正在尝试在 Windows 通用应用程序中使用串行端口。我一直在使用 Microsoft 的 Serial Sample 应用程序作为模板,但是我遇到了一个相当奇怪的问题。

var dis = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelectorFromUsbVidPid(0x04D8, 0x000A));
var sp = await SerialDevice.FromIdAsync(dis[0].Id);

这是一个失败的片段。它与原始样本略有不同,因为它连接到具有特定供应商的第一台设备。现在,如果我将此代码段放入 Microsoft 生成的示例应用程序中,串行端口将打开,一切正常。但是,当我将这段代码移到我自​​己的项目中时,它总是从该方法返回 null

这是来自 Microsoft 示例的完整 MainPage.xaml.cs 以及我的提醒: 这有效!!

// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
using System.Threading;
using System.Threading.Tasks;

namespace SerialSample
{    
  public sealed partial class MainPage : Page
  {
    /// <summary>
    /// Private variables
    /// </summary>
    private SerialDevice serialPort = null;
    DataWriter dataWriteObject = null;
    DataReader dataReaderObject = null;

    private ObservableCollection<DeviceInformation> listOfDevices;
    private CancellationTokenSource ReadCancellationTokenSource;

    public MainPage()
    {
        this.InitializeComponent();            
        comPortInput.IsEnabled = false;
        sendTextButton.IsEnabled = false;
        listOfDevices = new ObservableCollection<DeviceInformation>();
        ListAvailablePorts();
    }

    /// <summary>
    /// ListAvailablePorts
    /// - Use SerialDevice.GetDeviceSelector to enumerate all serial devices
    /// - Attaches the DeviceInformation to the ListBox source so that DeviceIds are displayed
    /// </summary>
    private async void ListAvailablePorts()
    {
        try
        {
            string aqs = SerialDevice.GetDeviceSelector();
            var dis = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelectorFromUsbVidPid(0x04D8, 0x000A));
            serialPort = await SerialDevice.FromIdAsync(dis[0].Id);

            status.Text = "Select a device and connect";

            for (int i = 0; i < dis.Count; i++)
            {
                listOfDevices.Add(dis[i]);
            }

            DeviceListSource.Source = listOfDevices;
            comPortInput.IsEnabled = true;
            ConnectDevices.SelectedIndex = -1;

            try
            {


                // Disable the 'Connect' button 
                comPortInput.IsEnabled = false;

                // Configure serial settings
                serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.BaudRate = 9600;
                serialPort.Parity = SerialParity.None;
                serialPort.StopBits = SerialStopBitCount.One;
                serialPort.DataBits = 8;
                serialPort.Handshake = SerialHandshake.None;

                // Display configured settings
                status.Text = "Serial port configured successfully: ";
                status.Text += serialPort.BaudRate + "-";
                status.Text += serialPort.DataBits + "-";
                status.Text += serialPort.Parity.ToString() + "-";
                status.Text += serialPort.StopBits;

                // Set the RcvdText field to invoke the TextChanged callback
                // The callback launches an async Read task to wait for data
                rcvdText.Text = "Waiting for data...";

                // Create cancellation token object to close I/O operations when closing the device
                ReadCancellationTokenSource = new CancellationTokenSource();

                // Enable 'WRITE' button to allow sending data
                sendTextButton.IsEnabled = true;

                Listen();
            }
            catch (Exception ex)
            {
                status.Text = ex.Message;
                comPortInput.IsEnabled = true;
                sendTextButton.IsEnabled = false;
            }
        }
        catch (Exception ex)
        {
            status.Text = ex.Message;
        }
    }

    /// <summary>
    /// comPortInput_Click: Action to take when 'Connect' button is clicked
    /// - Get the selected device index and use Id to create the SerialDevice object
    /// - Configure default settings for the serial port
    /// - Create the ReadCancellationTokenSource token
    /// - Start listening on the serial port input
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void comPortInput_Click(object sender, RoutedEventArgs e)
    {
        var selection = ConnectDevices.SelectedItems;

        if (selection.Count <= 0)
        {
            status.Text = "Select a device and connect";
            return;
        }

        DeviceInformation entry = (DeviceInformation)selection[0];         

        try
        {                
            serialPort = await SerialDevice.FromIdAsync(entry.Id);

            // Disable the 'Connect' button 
            comPortInput.IsEnabled = false;

            // Configure serial settings
            serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
            serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);                
            serialPort.BaudRate = 9600;
            serialPort.Parity = SerialParity.None;
            serialPort.StopBits = SerialStopBitCount.One;
            serialPort.DataBits = 8;
            serialPort.Handshake = SerialHandshake.None;

            // Display configured settings
            status.Text = "Serial port configured successfully: ";
            status.Text += serialPort.BaudRate + "-";
            status.Text += serialPort.DataBits + "-";
            status.Text += serialPort.Parity.ToString() + "-";
            status.Text += serialPort.StopBits;

            // Set the RcvdText field to invoke the TextChanged callback
            // The callback launches an async Read task to wait for data
            rcvdText.Text = "Waiting for data...";

            // Create cancellation token object to close I/O operations when closing the device
            ReadCancellationTokenSource = new CancellationTokenSource();

            // Enable 'WRITE' button to allow sending data
            sendTextButton.IsEnabled = true;

            Listen();
        }
        catch (Exception ex)
        {
            status.Text = ex.Message;
            comPortInput.IsEnabled = true;
            sendTextButton.IsEnabled = false;
        }
    }

    /// <summary>
    /// sendTextButton_Click: Action to take when 'WRITE' button is clicked
    /// - Create a DataWriter object with the OutputStream of the SerialDevice
    /// - Create an async task that performs the write operation
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void sendTextButton_Click(object sender, RoutedEventArgs e)
    {
        try
        {                
            if (serialPort != null)
            {
                // Create the DataWriter object and attach to OutputStream
                dataWriteObject = new DataWriter(serialPort.OutputStream);

                //Launch the WriteAsync task to perform the write
                await WriteAsync();
            }
            else
            {
                status.Text = "Select a device and connect";                
            }
        }
        catch (Exception ex)
        {
            status.Text = "sendTextButton_Click: " + ex.Message;
        }
        finally
        {
            // Cleanup once complete
            if (dataWriteObject != null)
            {
                dataWriteObject.DetachStream();
                dataWriteObject = null;
            }
        }
    }

    /// <summary>
    /// WriteAsync: Task that asynchronously writes data from the input text box 'sendText' to the OutputStream 
    /// </summary>
    /// <returns></returns>
    private async Task WriteAsync()
    {
        Task<UInt32> storeAsyncTask;

        if (sendText.Text.Length != 0)
        {
            // Load the text from the sendText input text box to the dataWriter object
            dataWriteObject.WriteString(sendText.Text);                

            // Launch an async task to complete the write operation
            storeAsyncTask = dataWriteObject.StoreAsync().AsTask();

            UInt32 bytesWritten = await storeAsyncTask;
            if (bytesWritten > 0)
            {                    
                status.Text = sendText.Text + ", ";
                status.Text += "bytes written successfully!";
            }
            sendText.Text = "";
        }
        else
        {
            status.Text = "Enter the text you want to write and then click on 'WRITE'";
        }
    }

    /// <summary>
    /// - Create a DataReader object
    /// - Create an async task to read from the SerialDevice InputStream
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void Listen()
    {
        try
        {
            if (serialPort != null)
            {
                dataReaderObject = new DataReader(serialPort.InputStream);

                // keep reading the serial input
                while (true)
                {
                    await ReadAsync(ReadCancellationTokenSource.Token);
                }
            }
        }
        catch (Exception ex)
        {
            if (ex.GetType().Name == "TaskCanceledException")
            {
                status.Text = "Reading task was cancelled, closing device and cleaning up";
                CloseDevice();
            }
            else
            {
                status.Text = ex.Message;
            }
        }
        finally
        {
            // Cleanup once complete
            if (dataReaderObject != null)
            {
                dataReaderObject.DetachStream();
                dataReaderObject = null;
            }
        }
    }

    /// <summary>
    /// ReadAsync: Task that waits on data and reads asynchronously from the serial device InputStream
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    private async Task ReadAsync(CancellationToken cancellationToken)
    {
        Task<UInt32> loadAsyncTask;

        uint ReadBufferLength = 1024;

        // If task cancellation was requested, comply
        cancellationToken.ThrowIfCancellationRequested();

        // Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
        dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;

        // Create a task object to wait for data on the serialPort.InputStream
        loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);

        // Launch the task and wait
        UInt32 bytesRead = await loadAsyncTask;
        if (bytesRead > 0)
        {
            rcvdText.Text = dataReaderObject.ReadString(bytesRead);
            status.Text = "bytes read successfully!";
        }            
    }

    /// <summary>
    /// CancelReadTask:
    /// - Uses the ReadCancellationTokenSource to cancel read operations
    /// </summary>
    private void CancelReadTask()
    {         
        if (ReadCancellationTokenSource != null)
        {
            if (!ReadCancellationTokenSource.IsCancellationRequested)
            {
                ReadCancellationTokenSource.Cancel();
            }
        }         
    }

    /// <summary>
    /// CloseDevice:
    /// - Disposes SerialDevice object
    /// - Clears the enumerated device Id list
    /// </summary>
    private void CloseDevice()
    {            
        if (serialPort != null)
        {
            serialPort.Dispose();
        }
        serialPort = null;

        comPortInput.IsEnabled = true;
        sendTextButton.IsEnabled = false;            
        rcvdText.Text = "";
        listOfDevices.Clear();               
    }

    /// <summary>
    /// closeDevice_Click: Action to take when 'Disconnect and Refresh List' is clicked on
    /// - Cancel all read operations
    /// - Close and dispose the SerialDevice object
    /// - Enumerate connected devices
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void closeDevice_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            status.Text = "";
            CancelReadTask();
            CloseDevice();
            ListAvailablePorts();
        }
        catch (Exception ex)
        {
            status.Text = ex.Message;
        }          
    }        
  }
}

下一个 block 如果来 self 的代码。 ConnectToSerialPort() 中的前两行与之前的测试相同,但是 SerialDevice.FromIdAsync(dis[0].id); 始终为空。 这行不通!!

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;

namespace OpenLab.Kitchen.Receiver
{
public sealed partial class MainPage : Page
{
    private List<byte> Bytes { get; set; }

    public MainPage()
    {
        this.InitializeComponent();
        Bytes = new List<byte>();
        ConnectToSerialPort();
    }

    private async void ConnectToSerialPort()
    {
        var dis = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelectorFromUsbVidPid(0x04D8, 0x000A));
        var sp = await SerialDevice.FromIdAsync(dis[0].Id);

        Debug.WriteLine(sp.UsbVendorId);

        DeviceInformationCollection serialDevices;

        while ((serialDevices = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelectorFromUsbVidPid(0x04D8, 0x000A))).Count < 1)
        {
            Debug.WriteLine("Unable to locate...");
        }

        SerialDevice serialPort;

        while ((serialPort = await SerialDevice.FromIdAsync(serialDevices[0].Id)) == null)
        {
            Debug.WriteLine("Failed to open serial port...");
        }

        serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
        serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
        serialPort.BaudRate = 9600;
        serialPort.Parity = SerialParity.None;
        serialPort.StopBits = SerialStopBitCount.One;
        serialPort.DataBits = 8;
        serialPort.Handshake = SerialHandshake.None;

        var dataReader = new DataReader(serialPort.InputStream);
        var buffer = new byte[1024];

        while (true)
        {
            var bytesRead = await dataReader.LoadAsync((uint)buffer.Length);
            dataReader.ReadBytes(buffer);
            Bytes.AddRange(buffer.Take((int)bytesRead));

            byte[] slipPacket;
            while ((slipPacket = Slip.ExtractSlipPacket(Bytes)) != null)
            {
                var waxPacket = WaxPacketConverter.FromBinary(slipPacket, DateTime.Now);
                if (waxPacket != null)
                {
                    Debug.WriteLine(waxPacket);
                }
            }
        }
    }
  }
}

我已经检查了所有 list 权限以匹配它们并检查了诸如引用的 DLL 版本之类的东西,一切看起来都一样。还检查了像以管理员身份运行 VS 之类的事情,我没有同时打开两个应用程序,所以它不是应该保持端口打开或任何东西......

有没有人有什么想法?

最佳答案

因此,Microsoft 没有提到您需要向应用程序 list 中添加一些内容以进行串行通信,也没有在应用程序 list GUI 中为串行通信勾选复选框。

需要将以下内容添加到您的应用程序 list (如果不存在,请创建 <Capabilities> 部分):

<Capabilities>
  <DeviceCapability Name="serialcommunication">
    <Device Id="any">
      <Function Type="name:serialPort" />
    </Device>
  </DeviceCapability>
</Capabilities>

更新 10/2016

Microsoft 已更新其文档以反射(reflect)此要求。

https://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.serialcommunication.aspx

关于c# - Windows 通用应用程序串行端口无法打开,SerialDevice.FromIdAsync 始终为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34160376/

相关文章:

c# - 未从FirstOrDefault公开的可为空的引用类型信息

windows - Ack 有时不会显示行号并且失去着色

python - 在 windows anaconda 中安装 tensorflow - 并使用 Spyder GUI 运行它

windows - Python模块以指定的频率和长度发出Windows主板扬声器的哔哔声?

c# - c#从串口读取字符

linux - 如何永久禁用 stty 的 XON/XOFF 设​​置?

python - 如何在 python 串口上写入 ttyUSB0 将被解释的命令?

c# - 反序列化使用不同版本的已签名程序集编写的泛型的最佳方法是什么?

javascript - C# 如何使用 javascript 或 jquery 调用 MVC Controller 功能

c# - 如何使用 Java 在 Windows 上创建虚拟磁盘(letter、share 等)?