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

时间:2018-01-15 08:08:45

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

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

编辑:在做了一些额外的故障排除后,我发现了以下内容 - 当我尝试停止调试时,Visual Studio冻结(无法进行UI交互,但调试监控仍在更新),并且停止此操作的唯一方法是拔出我的笔记本电脑(和串口到USB电缆)对接,此时VS再次正常运行。此外,我似乎得到错误"请求的资源正在使用中。 (HRESULT的例外情况:0x800700AA)"在串口上的while(true)循环的第二次迭代中不起作用。

调用串口的代码是:

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

    }

我知道我可能只是在做一些愚蠢的事情,但任何帮助都会非常感激。在这一点上,我只是想让它在普通PC上工作,然后才能开始处理Pi上的驱动程序问题等。

1 个答案:

答案 0 :(得分:0)

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