How to write your own Get / Request function with serial port data?

…衆ロ難τιáo~ 提交于 2019-12-11 15:55:17

问题


I have a class that talks to a serial port and I want to mimic a Get function. The problem is, the serial port feeds in raw data which may or may not come. It also has to be processed and parsed. For example, if I want to get a Person object, the serial port class does this.

  1. A method to send the request for a Person.

  2. Something happens on the serial device... it might respond, it might not.

  3. Bytes come in through an event handler that processes and parses all data, and eventually a Person object.

I want to wrap that all up into a "GetPerson" function but I'm having difficulty connecting steps in 1 and 3. Step 3 is a function that is always running and is more of a generic parser.

Can someone help me design/structure this?

Edit: Also I've tried using a class variable and checking via while statement as shown below but it doesn't check the variable during the while statement for whatever reason:

private Person person;

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

回答1:


As far as I understood you need to convert EAP to TAP. In other words to wait for some data receiving event in async\await manner. You can use TaskComplettionSource<> for that. Based on this article I tried to imagine the design appropriate solution:

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: timeout logic is added, see also this question.

Hope it helps.



来源:https://stackoverflow.com/questions/52195772/how-to-write-your-own-get-request-function-with-serial-port-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!