c# - 无法从 UWP 应用程序中的 2 个串行设备读取

标签 c# uwp raspberry-pi windows-10-iot-core

希望这里有人能够帮助我。我正在创建一个 c# UWP 应用程序以在 Raspberry Pi2/Windows IOT 核心上运行。我需要从 2 个串行设备(由外部按钮/PLC 触发)读取输入以计算一些值。我一次可以读取其中一个设备,但到目前为止还无法获得两者的值。我的序列代码基于一个例子,我试图从主页调用它。到目前为止,无论我做了什么更改,第一个设备返回一个值,第二个不返回(串行处理程序中等待的任务立即返回 null,而不是等待一个值通过串行端口传来)。

编辑:在进行了一些额外的故障排除后,我发现了以下内容 - 当我尝试停止调试时,Visual Studio 卡住(无法进行 UI 交互,但调试监控仍在更新),停止此操作的唯一方法是拔掉插头我的笔记本电脑(以及串行到 USB 电缆)的底座,此时 VS 再次正常运行。此外,我似乎在串行端口上 while(true) 循环的第二次迭代中收到错误“请求的资源正在使用中。(HRESULT 异常:0x800700AA)”不起作用。

调用串口的代码为:

private async Task listenForDeviceInput()
    {
        string weight;
        string area;
        //var areaTask =  cognosCamera.Listen();
        //var  weightTask =  weighTable.Listen();
        Task <string>  areaTask =  cognosCamera.Listen();
        Task <string> weightTask =  weighTable.Listen();
        await Task.WhenAll(areaTask, weightTask);
        weight = await weightTask;
        area = await areaTask;


        weight = weight.TrimEnds("\r");
        area = area.TrimEnds("\r");
        AddNewHide(weight, area);
        saveHide();
        listenForDeviceInput(); //removed the await here to see what happens

    }

串行处理在这里:

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

using System;
using System.Collections.ObjectModel;
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 SerialDeviceHandler
{
    public sealed partial class SerialPort
    {
        /// <summary>
        /// Private variables
        /// </summary>
        private SerialDevice serialPort = null;
        DataWriter dataWriteObject = null;
        DataReader dataReaderObject = null;

        private ObservableCollection<DeviceInformation> listOfDevices;
        private CancellationTokenSource ReadCancellationTokenSource;



        /// <summary>
        /// ListAvailablePorts
        /// - Use SerialDevice.GetDeviceSelector to enumerate all serial devices
        /// - Attaches the DeviceInformation to the ListBox source so that DeviceIds are displayed
        /// </summary>


        /// <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>
        public async Task OpenSerialPort(string entry)
        {


            try
            {
                serialPort = await SerialDevice.FromIdAsync(entry);
                if (serialPort == null) return;



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



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



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



        /// <summary>
        /// WriteAsync: Task that asynchronously writes data from the input text box 'sendText' to the OutputStream 
        /// </summary>
        /// <returns></returns>


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

                    // keep reading the serial input
                    while (true)
                    {
                        result = await ReadAsync(ReadCancellationTokenSource.Token);
                        if(result != "Nothing" || result == null)
                        {
                            return result;
                        }
                    }
                }
                return "Failed";
            }
            catch (TaskCanceledException tce)
            {
                //status.Text = "Reading task was cancelled, closing device and cleaning up";
                CloseDevice();
                return "Task Cancelled";
            }
            catch (Exception ex)
            {
                //status.Text = ex.Message;
                return "Task Errored";
            }
            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<string> 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;

            using (var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
            {
                // Create a task object to wait for data on the serialPort.InputStream
                loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(childCancellationTokenSource.Token);

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

        /// <summary>
        /// CancelReadTask:
        /// - Uses the ReadCancellationTokenSource to cancel read operations
        /// </summary>
        public 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;
            }
        }
    }

据我所知,这 2 个串行端口对象似乎已正确创建(基于这样一个事实:如果我注释掉另一个的初始化,我可以从每个对象中获取一个值)。我将 2 个串行对象初始化为:

private async System.Threading.Tasks.Task InitializeSerialDevicesAsync()
    {
        weighTable = new SerialPort();
        cognosCamera = new SerialPort();
        await weighTable.OpenSerialPort(scaleComPort);
        await cognosCamera.OpenSerialPort(cameraComPort);

    }

我知道我可能只是在做一些愚蠢的事情,但我们将不胜感激任何帮助。在这一点上,我只是想在我必须开始处理 Pi 上的驱动程序问题等之前让它在普通 PC 上运行。

最佳答案

好的 - 所以我已经解决了问题,但不太明白为什么。我将 USB 转串行电缆更换为不同品牌(从 prolific 到 FTDI),现在应用程序在笔记本电脑和 pi 上都能正常运行。

关于c# - 无法从 UWP 应用程序中的 2 个串行设备读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48259030/

相关文章:

c# - ClosedXML 将数据添加到现有表

c# - 处理聚合的所有事件

c# - 在 DataTemplate 中绑定(bind) ElementName

uwp - Xamarin form-UWP - 在列表快速滚动时显示数据之前的黑色单元格

.net - .NET Native 是否将所有泛型编译为 native 代码?

bash - 树莓派的 GPIO 命令无法通过 crontab 工作

c# - 如何从 SSL key 文件创建 RsaSecurityKey 实例

c# - 无法将 COM 对象转换为类类型

mono - 在树莓派上编译 Mono 3.x

android - 我应该使用哪种外部显示设备来检查 Android 的东西