Как написать собственную функцию Get/Request с данными последовательного порта?

У меня есть класс, который взаимодействует с последовательным портом, и я хочу имитировать функцию Get. Проблема в том, что последовательный порт передает необработанные данные, которые могут прийти или не прийти. Его также необходимо обработать и разобрать. Например, если я хочу получить объект Person, класс последовательного порта сделает это.

  1. Метод отправки запроса для Person.

  2. Что-то происходит на последовательном устройстве... оно может ответить, а может и нет.

  3. Байты поступают через обработчик событий, который обрабатывает и анализирует все данные и, в конечном итоге, объект Person.

Я хочу обернуть все это в функцию «GetPerson», но у меня возникают трудности с соединением шагов в 1 и 3. Шаг 3 — это функция, которая всегда выполняется и представляет собой скорее общий анализатор.

Может ли кто-нибудь помочь мне спроектировать/структурировать это?

Изменить: также я пытался использовать переменную класса и проверять с помощью оператора while, как показано ниже, но по какой-либо причине он не проверяет переменную во время оператора while:

private Person person;

public Person GetPerson()
{
   ...
   while (person == null) {}
   return person;
}

person Tong    schedule 06.09.2018    source источник
comment
Пожалуйста, предоставьте код, который работает с последовательным портом.   -  person KozhevnikovDmitry    schedule 06.09.2018


Ответы (1)


Насколько я понял, вам нужно преобразовать с EAP на TAP. Другими словами, ожидать какого-либо события получения данных в режиме async\await. Вы можете использовать TaskComplettionSource<> для этого. На основе в этой статье я попытался представить подходящее для дизайна решение:

public class PersonSerialPort : IDisposable
{
    private readonly SerialPort port;

    /// <summary>
    /// Timeout in milliseconds
    /// </summary>
    private const int Timeout = 5000;

    public PersonSerialPort()
    {
        // port initializing here
        port = new SerialPort(/*your parameters here*/);
        port.Open();
    }

    public async Task<Person> GetPerson()
    {
        // set up the task completion source
        var tcs = new TaskCompletionSource<Person>();

        // handler of DataReceived event of port
        var handler = default(SerialDataReceivedEventHandler);
        handler = (sender, eventArgs) =>
        {
            try
            {
                Person result = new Person();

                // some logic for filling Person fields
                // or set it null or whatever you need
                // you are free to not set result and wait for next event fired too

                tcs.SetResult(result);

            }
            finally
            {
                port.DataReceived -= handler;
            }
        };
        port.DataReceived += handler;

        // send request for person
        port.Write("Give a person number 1");

        if (await Task.WhenAny(tcs.Task, Task.Delay(Timeout)) == tcs.Task)
        {
            return tcs.Task.Result;
        }
        else
        {
            port.DataReceived -= handler;
            throw new TimeoutException("Timeout has expired");
        }
    }

    public void Dispose()
    {
        port?.Dispose();
    }
}

UPD: добавлена ​​логика тайм-аута, см. также этот вопрос.

Надеюсь, поможет.

person KozhevnikovDmitry    schedule 06.09.2018
comment
Спасибо за терминологию, она должна помочь мне с поиском. Я постараюсь понять это, прежде чем опробовать ваш код. - person Tong; 06.09.2018
comment
Хорошо, пока это выглядит хорошо. Я предполагаю, что мой последний вопрос относительно этого заключается в том, как тайм-аут обработчика. Я читал об CancellationTokens, но они применяются только к задачам, а не к делегатам. - person Tong; 07.09.2018
comment
Я добавил логику тайм-аута. Видите ли, этого можно достичь с помощью второй задачи и Task.WhenAny() подхода. Не забудьте отписаться от DataReceived события. - person KozhevnikovDmitry; 07.09.2018
comment
Это действительно открыло для меня новое окно. Спасибо! - person Tong; 07.09.2018
comment
Рад помочь =) - person KozhevnikovDmitry; 07.09.2018