Исключение считывателя данных SerialDevice UWP: 0x800710DD. Идентификатор операции недействителен - PullRequest
0 голосов
/ 27 марта 2020

Я работаю над переносом функциональности из примера Windows Forms App в приложение Xamarin.Forms UWP, в котором оно должно выполнять запись и чтение с устройства Bluetooth на COM-порту. У меня это работает нормально большую часть времени, но периодически приложение UWP переходит в состояние, когда любой вызов dataReader.LoadAsyn c вызовет исключение:

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 не только прекрасно работает (с тем же устройством Bluetooth) даже после того, как оно перейдет в это состояние, но и просто открывает порт и читает из Устройство (в старом приложении) фактически устраняет проблему в приложении UWP на некоторое время, позволяя мне снова читать с устройства.

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Это может быть связано с асинхронными методами. Вы можете попробовать это:

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

Для асинхронных методов (таких как DataReader.LoadAsync) события происходят в потоке пользовательского интерфейса и могут быть инициированы только один раз, и могут продолжаться только после предыдущего асинхронного метода. выполнен. Ваш вопрос может быть связан с этим.

0 голосов
/ 30 марта 2020

В итоге выясняется, что причиной проблемы был метод LoadAsyn c, зависший при ожидании заполнения всего буфера (1024 байта), несмотря на то, что для InputStreamOptions установлено значение Partial. Исключение, которое я получал, было несколько не связано и было связано с тем, что асинхронный метод не работал должным образом (метод вызывался снова, когда первая задача не была выполнена).

Исправление представляло собой комбинацию добавления ReadTimeout к SerialDevice:

_currentSerialDevice.ReadTimeout = TimeSpan.FromMilliseconds(500);

, а также оборачивая саму задачу LoadAsyn c в токен отмены по времени:

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

Это позволило методу LoadAsyn c завершить оба процесса, когда устройство потребляло менее 1024 байтов (обработано SerialDevice.ReadTimeout), а также когда устройство потребляло 0 байтов (обработано CancellationToken).

Я до сих пор не уверен, зачем запускать win Приложение форм некоторое время решало проблему, возможно, оно устанавливало ReadTimeout (в то время как мое приложение UWP не было), и это каким-то образом сохранялось на последовательном порту.

...