4

I have read a few threads here suggesting to use port.BaseStream.ReadAsync() with waith async / await. What is not clear to me is what is the best way to implement this?

Do i still use the event_handler and just make it async / awaitable ?

private async void myPort_DataReceived(object sender,      SerialDataReceivedEventArgs e)
        {
            byte[] buffer = new byte[myPort.BytesToRead];
            await (myPort.BaseStream.ReadAsync(buffer, 0, buffer.Length));
        }

Or is the event handler ignored completely and instead i am calling ReadAsync in a loop?

Edit: Once parsed, I will be 1) Sending the data to a TCP Server and 2) Write it to sq3lite database.

user1957413
  • 105
  • 1
  • 12
  • We have a tag system in the questions, you don't need to put tags in the title too. – Scott Chamberlain Oct 20 '15 at 01:13
  • can you give more details about your question? what is "myPort"? what is "SerialPort"? – Xiaomin Wu Oct 20 '15 at 01:14
  • 1
    @XiaominWu [`SerialPort`](https://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx) is a class in the .NET framwork for communicating with COM ports. @user1957413, Please show how you are going to use this data, we can't tell you how to do it unless you explain what you are trying to do. Update your question with a example showing how you would do it without async/await and we will show you how to use the async API. – Scott Chamberlain Oct 20 '15 at 01:15

1 Answers1

5

Microsoft has updated the API which can allow for a relatively simple async read and write implementation. Please note that you would not implement the synchronous event handler which is what you appear to have done, but simply call this function whenever you expect to receive data on the COM port:

public async Task<Stream> ReceiveData()
{
    var buffer = new byte[4096];
    int readBytes = 0;
    SerialPort port = new SerialPort(/* ... */);
    using (MemoryStream memoryStream = new MemoryStream())
    {
        while ((readBytes = await port.BaseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            memoryStream.Write(buffer, 0, readBytes);
        }

        return memoryStream;
    }
}

Here is another alternative implementation (see http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport) where the author explains problems with the SerialPort DataReceived, BytesToRead, and other API members. Instead of using the SerialPort API because he indicates it has been poorly designed, implemented and tested he suggests this methodology using the BaseStream:

Action kickoffRead = null;
kickoffRead = delegate {
    port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar) {
        try {
            int actualLength = port.BaseStream.EndRead(ar);
            byte[] received = new byte[actualLength];
            Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
            raiseAppSerialDataEvent(received);
        }
        catch (IOException exc) {
            handleAppSerialError(exc);
        }
        kickoffRead();
    }, null);
};
kickoffRead();

Please note that the performance improvements I have found using the BCL with BaseStream are many orders of magnitude better than using the SerialPort API.

user8128167
  • 6,929
  • 6
  • 66
  • 79
  • Thank you, though it would be very helpful if you could elaborate a bit on the second solution. I found the article you linked before finding this page. But I didn't really understand how his solution works so I continued searching. Also, this article was written quite a while ago. Is this still the case that the native API still lacking in the regards he described? – Curtwagner1984 Jul 04 '22 at 04:59
  • Also, the article says that newer .NET versions have a `readAsync` methods to the `BaseStream` class. Maybe it's better to use them? – Curtwagner1984 Jul 04 '22 at 05:03
  • Thanks for the updates. I am no longer with the same employer so I don't have the equipment to research and test. – user8128167 Jul 05 '22 at 19:51