Приложение UWP замедляется, а затем аварийно завершает работу после определенного количества последовательных операций записи

Я делаю приложение с использованием Windows IoT Core на Raspberry Pi 3.

Я пытаюсь связаться с Arduino, используя последовательную связь. Я использовал большинство методов, показанных в этом примере, на GitHub для создания последовательного устройства и записи на него: https://github.com/ms-iot/samples/tree/develop/SerialSample/CS.

Программа работает нормально в течение первых 130 байтов или около того, но затем начинает резко замедляться после этого и аварийно завершает работу примерно на 135-м байте или около того.

Иногда это приводит к тому, что Raspberry Pi отображает «синий экран смерти» Windows 10, сообщая о необходимости перезагрузки.

Я пытался переписать код многими способами и использовать различные варианты async, task и await, но, похоже, не могу заставить его работать.

Вот код, который я использую для инициализации последовательного устройства:

private async void setup()
{
    serialPort = await initializeSerial();
}

private async Task<SerialDevice> initializeSerial()
{
    try
    {
        string aqs = SerialDevice.GetDeviceSelector();
        var dis = await DeviceInformation.FindAllAsync(aqs);

        for (int i = 0; i < dis.Count; i++)
        {
            if (dis[i].Name.Contains("Arduino Uno"))
            {
                var serialPort = await SerialDevice.FromIdAsync(dis[i].Id);

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

                // Display configured settings
                //Debug.WriteLine("Serial port configured successfully.");

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


                return serialPort;
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }

    return null;
}

и вот код, который я использую для записи на последовательное устройство:

private async void sendString(string stringToSend)
{
    try
    {
        if (serialPort != null)
        {
            // Create the DataWriter object and attach to OutputStream
            dataWriteObject = new DataWriter(serialPort.OutputStream);

            //Launch the WriteAsync task to perform the write
            await WriteAsync(stringToSend);
        }
        else
        {
            status.Text = "Select a device and connect";
        }
    }
    catch (Exception ex)
    {
        status.Text = "sendString: " + ex.Message;
    }
    finally
    {
            // Cleanup once complete
            if (dataWriteObject != null)
            {
                dataWriteObject.DetachStream();
                dataWriteObject = null;
            }
    }
}

/// <summary>
/// WriteAsync: Task that asynchronously writes data from the input text box 'sendText' to the OutputStream 
/// </summary>
/// <returns></returns>
private async Task WriteAsync(string stringToWrite)
{
    Task<UInt32> storeAsyncTask;

    dataWriteObject.WriteString(stringToWrite);                

    // Launch an async task to complete the write operation
    storeAsyncTask = dataWriteObject.StoreAsync().AsTask();

    UInt32 bytesWritten = await storeAsyncTask;
    if (bytesWritten > 0)
    {
        counter++;
        status.Text = stringToWrite + ", ";
        status.Text += "bytes written successfully! (" + counter + ")";
    }       
}

Любая помощь/совет будут оценены.

Обновлять

Я переписал свой метод sendString следующим образом и упростил его с помощью оператора using:

private async void sendString(string stringToSend)
{
    using (DataWriter dataWriter = new DataWriter(serialPort.OutputStream))
    {
        dataWriter.WriteString(stringToSend);
        await dataWriter.StoreAsync();
        //await dataWriter.FlushAsync();
        dataWriter.DetachStream();

        counter++;
        status.Text = stringToSend + ", ";
        status.Text += "bytes written successfully! (" + counter + ")";
    }
}

Однако проблема все еще сохраняется.


person Connor Joseph Early    schedule 23.06.2016    source источник
comment
Я полагаю, что у вашего DataWriter может быть несколько проблем. Как правило, все, что является IDisposable (имеет метод .Dispose()), я помещаю в оператор using и создаю новый каждый раз, когда я use один. В вашем коде я могу только предположить, что dataWriteObject является полем внутри класса? Если это так, я бы подумал об удалении его как поля и using по одному каждый раз, когда вы пишете. Является ли ваше dataWriteObject полем?   -  person Geoff James    schedule 23.06.2016
comment
Спасибо, @Джефф. Да, я не включил его в эти примеры кода, но мой dataWriteObject это приватное поле внутри класса.   -  person Connor Joseph Early    schedule 23.06.2016
comment
Я не уверен в вашем опыте работы с C# - не могли бы вы сказать мне, использовали ли вы операторы using раньше?   -  person Geoff James    schedule 23.06.2016
comment
@GeoffJames, нет, я новичок в C#. Пользуюсь около трех недель. Я использовал только операторы using в верхней части файла для включения пространств имен.   -  person Connor Joseph Early    schedule 23.06.2016
comment
Я понимаю. Эти using такие же, как import в некоторых других языках. Я бы предложил удалить ваше dataWriteObject как личное поле и создавать new в блоке using каждый раз, когда вам нужно его использовать. Я не говорю, что это точная проблема - может быть, но это, безусловно, очень поможет. Используйте свою любимую поисковую систему для использования using блоков с IDisposable объектами. Например: using (var writer = new DataWriter(serialPort.OutputStream)) { ... // Your code to write in here ... // and end the block when you're finished }. Дайте знать, как у вас дела :)   -  person Geoff James    schedule 23.06.2016
comment
@GeoffJames, из любопытства, как вы думаете, моя проблема как-то связана с заполнением какого-то буфера? Я пытался использовать метод FlushAsync() раньше, но каждый раз, когда я это делаю, я получаю исключение NotImplemented. Мне интересно, имеет ли это какое-либо отношение к этому: не реализовано?forum=wpdevelop" rel="nofollow noreferrer">social.msdn.microsoft.com/Forums/Windowsapps/en-US/   -  person Connor Joseph Early    schedule 24.06.2016
comment
Не видя остальной части вашего кода, я не совсем уверен, где вы очищаете буфер или обрабатываете входящие байты и т. д., но, глядя на этот пост, похоже, что другие люди испытывают то же самое с вашим исключением. Я думаю, что у вас может быть несколько проблем, смешанных вместе, и может быть лучше начать снова с самого начала (если вы еще не написали слишком много) и останавливаться на разных этапах, чтобы убедиться, что все работает нормально :)   -  person Geoff James    schedule 24.06.2016
comment
@GeoffJames, я начал с самого начала и переписал вещи, используя оператор «using» с объектом DataWriter, но все равно не повезло. Я думаю, проблема в том, что serialPort.OutputStream заполняется/не сбрасывается, а не в DataWriter. Есть ли у вас какие-либо дополнительные идеи?   -  person Connor Joseph Early    schedule 27.06.2016
comment
Я получаю BSOD на Windows 10 (на рабочем столе) при аналогичных обстоятельствах.   -  person Jeff    schedule 22.05.2017
comment
@Jeff Джефф, я не тестировал это на рабочем столе. К сожалению, я предполагаю, что мое решение не будет работать на настольном компьютере, поскольку, насколько я знаю, ваша единственная форма последовательной связи - через этот USB-порт. Надеюсь, вы разберетесь!   -  person Connor Joseph Early    schedule 23.05.2017


Ответы (1)


Я попытался использовать контакты UART вместо USB-кабеля для записи данных и больше не испытывал проблем. Вот код, который я использовал для инициализации шины UART на Pi, и я использовал ту же функцию для записи, что и выше:

private async Task<SerialDevice> initializeSerial()
{
    try
    {
        string aqs = SerialDevice.GetDeviceSelector("UART0");
        var dis = await DeviceInformation.FindAllAsync(aqs);

        SerialDevice serialPort = await SerialDevice.FromIdAsync(dis[0].Id);

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

        status.Text = "Serial port configured succesfully.";

        return serialPort;
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }

    status.Text = "Serial port not configured successfully. Are you sure a serial device is connected?";
    return null;
}

Это не совсем решает проблему с отправкой данных по USB-кабелю, но я размещаю его здесь на случай, если у кого-то возникнет аналогичная проблема с использованием USB-порта и он захочет попробовать это вместо этого.

person Connor Joseph Early    schedule 29.06.2016