【问题标题】:UWP SerialDevice DataReader Exception: 0x800710DD. The operation identifier is not validUWP 串行设备数据读取器异常:0x800710DD。操作标识符无效
【发布时间】:2020-07-08 12:49:58
【问题描述】:

我正在将功能从示例 Windows 窗体应用程序移植到 Xamarin.Forms UWP 应用程序,它应该在 COM 端口上写入和读取蓝牙设备。我大部分时间都可以正常工作,但 UWP 应用程序会间歇性地进入任何对 dataReader.LoadAsync 的调用都会触发异常的状态:

Exception thrown at 0x74AF1A62 (KernelBase.dll) in MyApp.UWP.exe: WinRT originate error - 0x800710DD : 'The operation identifier is not valid.'.
Exception thrown: 'System.Runtime.InteropServices.COMException' in MyApp.UWP.exe
WinRT information: The operation identifier is not valid.

重新启动应用程序或 Visual Studio 没有帮助,问题仍然存在。

最后一次发生它似乎并没有影响我的 dataWriter 写入设备,只影响后续读取。

所有代码都在 UWP 项目中。

private DataReader _dataReader;
private DataWriter _dataWriter;
private SerialDevice _currentSerialDevice;

private async Task ReadAsync(SerialDevice serialDevice)
{
    const uint ReadBufferLength = 1024;

    if (_dataReader == null)
    {                
        _dataReader = new DataReader(_currentSerialDevice.InputStream) { InputStreamOptions = InputStreamOptions.Partial };
    }

    uint bytesRead = await _dataReader.LoadAsync(ReadBufferLength); // <- exception here

    if (bytesRead > 0)
    {
        var vals = new byte[bytesRead];
        _dataReader.ReadBytes(vals);
        DoStuffWithBytes(vals);
    }
}

串行设备是从应用程序的列表中选择的。

// Get serial devices
DeviceInformationCollection serialDeviceCollection = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector());
// Load serial device from user choosing a device from serialDeviceCollection 

public async void ConnectToSerialDevice(DeviceInformation device)
{
    _currentSerialDevice = await SerialDevice.FromIdAsync(device.Id);

    _currentSerialDevice.BaudRate = 115200;
    _currentSerialDevice.Parity = SerialParity.None;
    _currentSerialDevice.DataBits = 8;
    _currentSerialDevice.StopBits = SerialStopBitCount.One;
    _currentSerialDevice.Handshake = SerialHandshake.RequestToSend;
}

写入设备的代码,即使处于奇数状态也能正常工作:

private async Task WriteToDevice(byte[] outBuffer)
{
    if (_currentSerialDevice != null)
    {
        if (_dataWriter == null)
        {
            _dataWriter = new DataWriter(_currentSerialDevice.OutputStream);
        }
        _dataWriter.WriteBytes(outBuffer);
        await _dataWriter.StoreAsync();
    }
}

我尝试过刷新数据写入器、每次都重新创建数据写入器和数据读取器等操作,但我仍然遇到相同的错误并且无法从设备读取任何内容。在正常操作中,我能够成功读取我期望的字节(即使没有要读取的字节,它也会“读取”0字节)并且可以毫无例外地输出这个结果。

关于这一切的奇怪之处在于,即使原始 Windows Forms 应用程序进入此状态后,它不仅可以正常工作(使用相同的蓝牙设备),而且只需打开端口并从设备读取(在旧的app) 实际上暂时修复了 UWP 应用程序中的问题,让我可以再次从设备读取。

【问题讨论】:

    标签: c# uwp serial-port


    【解决方案1】:

    这可能与异步方法有关。你可以试试这个:

    var task = await _dataReader.LoadAsync(ReadBufferLength);
    task.AsTask().Wait();
    uint bytesRead = task.GetResults();
    

    对于异步方法(如DataReader.LoadAsync),事件发生在UI线程上,只能触发一次,只有在上一个异步方法完成后才能继续触发。您的问题可能与此有关。

    【讨论】:

    • 感谢这个 Richard,它让我看到任务挂了很长时间,让我走上了寻找实际问题的正确轨道。
    【解决方案2】:

    最终发现问题的原因是尽管 InputStreamOptions 设置为 Partial,但 LoadAsync 方法在等待填充整个缓冲区(1024 字节)时挂起。我得到的异常有点无关紧要,与异步方法无法正常工作有关(当第一个任务未完成时再次调用该方法)。

    修复是向 SerialDevice 添加 ReadTimeout 的组合:

    _currentSerialDevice.ReadTimeout = TimeSpan.FromMilliseconds(500);
    

    并且还将 LoadAsync 任务本身包装在一个定时取消令牌中:

    using (var cts = new CancellationTokenSource(500))
    {
        var task = _dataReader.LoadAsync(ReadBufferLength);
        var readTask = task.AsTask(cts.Token);
        uint bytesRead = await readTask;
    }
    

    这允许 LoadAsync 方法在设备消耗少于 1024 个字节(由 SerialDevice.ReadTimeout 处理)和设备有 0 个字节消耗(由 CancellationToken 处理)时完成。

    我仍然不确定为什么运行 win forms 应用程序可以解决一段时间的问题,可能是它设置了 ReadTimeout(而我的 UWP 应用程序没有)并且这以某种方式持续存在于串行端口上。

    【讨论】:

      猜你喜欢
      • 2018-12-06
      • 1970-01-01
      • 2018-07-17
      • 2010-10-02
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      • 2017-03-07
      相关资源
      最近更新 更多