如何为serialDevice添加超时?

时间:2018-02-15 13:21:17

标签: c# uwp win-universal-app windows-10-universal

我目前正在开发一个项目,我使用带有UWP应用程序的串口。 有时我遇到的问题是我需要一定数量的数据,但是当我没有获得那么多的数据时,我的串口会一直读取,直到我手动取消它。

当我初始化serialDevice时,我设置了serialDevice.ReadTimeout参数但是没有做任何事情。 我还试图将cancellationToken绑定到ReadTimeout参数,但这也不起作用。如果我没记错的话,在它完成之前取消了我的方法...

有没有办法实现工作超时?

我用它作为我的基础:

public class ReadWriteAdapter
{
    public SemaphoreSlim Semaphore { get; }

    private static readonly object LockObject = new object();
    private static ReadWriteAdapter _instance;

    public static ReadWriteAdapter Current
    {
        get
        {
            if (_instance == null)
            {
                lock (LockObject)
                {
                    if (_instance == null)
                    {
                        _instance = new ReadWriteAdapter();
                    }
                }
            }
            return _instance;
        }
    }

    private ReadWriteAdapter()
    {
        Semaphore = new SemaphoreSlim(1, 1);
    }

    private SerialDevice _serialPort;

    public CancellationTokenSource ReadCancellationTokenSource;
    public CancellationTokenSource WriteCancellationTokenSource;

    private object _readCancelLock = new object();
    private object _writeCancelLock = new object();

    private DataWriter _dataWriter;
    private DataReader _dataReader;

    public bool IsDeviceInitialized()
    {
        return _serialPort != null;
    }


    public async Task<string> Init()
    {
        try
        {
            if (_serialPort != null) return "port already configured!";

            var aqs = SerialDevice.GetDeviceSelector("COM3");

            var devices = await DeviceInformation.FindAllAsync(aqs, null);

            if (!devices.Any()) return "no devices found!";

            await OpenPort(devices[0].Id);                

            WriteCancellationTokenSource = new CancellationTokenSource();
            ReadCancellationTokenSource = new CancellationTokenSource();

            return "found port!";

        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    private async Task OpenPort(string deviceId)
    {
        try
        {
            _serialPort = await SerialDevice.FromIdAsync(deviceId);

            if (_serialPort != null)
            {
                _serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                _serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
                _serialPort.BaudRate = 19200;
                _serialPort.Parity = SerialParity.None;
                _serialPort.StopBits = SerialStopBitCount.One;
                _serialPort.DataBits = 8;
                _serialPort.Handshake = SerialHandshake.None;

                _dataWriter = new DataWriter(_serialPort.OutputStream);
                _dataReader = new DataReader(_serialPort.InputStream);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

    }

    private async Task<byte[]> ReadAsync(CancellationToken cancellationToken, uint readBufferLength)
    {
        Task<uint> loadAsyncTask;
        var returnArray = new byte[readBufferLength];

        lock (_readCancelLock)
        {
            cancellationToken.ThrowIfCancellationRequested();

            _dataReader.InputStreamOptions = InputStreamOptions.Partial;

            loadAsyncTask = _dataReader.LoadAsync(readBufferLength).AsTask(cancellationToken);
        }

        var bytesRead = await loadAsyncTask;

        if (bytesRead > 0)
        {
            _dataReader.ReadBytes(returnArray);
        }
        return returnArray;
    }

    public async Task<uint> WriteCommand(string PairedCommand)
    {
        var commandArray = StringToByteArray(PairedCommand);

        uint taskResult = 0;

        try
        {
            if (_serialPort != null)
            {
                if (_dataWriter == null)
                {
                    _dataWriter = new DataWriter(_serialPort.OutputStream);

                    taskResult = await WriteAsync(WriteCancellationTokenSource.Token, commandArray);
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            _dataWriter.DetachStream();
            _dataWriter.Dispose();
            _dataWriter = null;
        }
        return taskResult;
    }

    public async Task<uint> WriteAsync(CancellationToken cancellationToken, byte[] data)
    {
        Task<uint> storeAsyncTask;

        try
        {
            lock (_writeCancelLock)
            {
                cancellationToken.ThrowIfCancellationRequested();

                _dataWriter.WriteBytes(data);

                storeAsyncTask = _dataWriter.StoreAsync().AsTask(cancellationToken);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return await storeAsyncTask;
    }        

    public async Task<byte[]> Listen(uint bufferLength)
    {
        var listen = new byte[bufferLength];

        try
        {
            if (_serialPort != null)
            {
                if (_dataReader == null)
                {
                    _dataReader = new DataReader(_serialPort.InputStream);
                }

                listen = await ReadAsync(ReadCancellationTokenSource.Token, bufferLength);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (_dataReader != null)
            {
                _dataReader.DetachStream();
                _dataReader.Dispose();
                _dataReader = null;
            }
        }
        return listen;
    }

    public byte[] StringToByteArray(string str)
    {
        var enc = new ASCIIEncoding();
        return enc.GetBytes(str);
    }

    public void CancelReadTask()
    {
        lock (_readCancelLock)
        {
            if (ReadCancellationTokenSource == null) return;
            if (ReadCancellationTokenSource.IsCancellationRequested) return;

            ReadCancellationTokenSource.Cancel();

            ReadCancellationTokenSource = new CancellationTokenSource();
        }
    }

    private void CancelWriteTask()
    {
        lock (_writeCancelLock)
        {
            if (WriteCancellationTokenSource == null) return;
            if (WriteCancellationTokenSource.IsCancellationRequested) return;

            WriteCancellationTokenSource.Cancel();

            WriteCancellationTokenSource = new CancellationTokenSource();
        }
    }
}

我用类似的代码(简短版)调用它:

public class ReadData
{
    private ReadBlock readBlock = new ReadBlock();

    public async Task<byte[]> ReadParaBlock()
    {
        await ReadWriteAdapter.Current.Semaphore.WaitAsync();

        await ReadWriteAdapter.Current.WriteCommand("getData");

        byte[] recievedArray = await ReadWriteAdapter.Current.Listen(100);

        ReadWriteAdapter.Current.Semaphore.Release();

        return recievedArray;            
    }                  
}

0 个答案:

没有答案