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

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

  1. Способ отправки запроса на Персона.

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

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

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

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

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

private Person person;

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

1 Ответ

0 голосов
/ 06 сентября 2018

Насколько я понял, вам нужно конвертировать EAP в TAP .Другими словами, ждать некоторого события получения данных в асинхронном порядке.Вы можете использовать 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: добавлена ​​логика тайм-аута, см. Также этот вопрос .

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

...