I need some help reading data from a serial port connected to a device with an RS-232 interface. I decided to use an async
/await
style since there will be data constantly updating in a GUI, which should remain user-responsive.
The code below is the essence of my current implementation.
private async void MyReadFromSerialPortMethod()
{
// (this.serialPort is a System.IO.Ports.SerialPort instance.)
this.serialPort.DiscardInBuffer();
this.serialPort.DiscardOutBuffer();
this.serialPort.Write(/* bytes for "please send me some data now", 0, length */);
byte[] header = new byte[3];
await this.serialPort.BaseStream.ReadAsync(header, 0, header.Length);
// do something with the header info first,
// like check what kind of data is incoming
byte[] data = new byte[5];
await this.serialPort.BaseStream.ReadAsync(data, 0, data.Length);
// do something with the data,
// like show it to the user eventually
}
My issue is that, in the above code, the ReadAsync
calls usually only read one byte from the input and then return from await
(not always, but usually). If I were using synchronous methods, I could arrange for ReceivedBytesThreshold
to contain the requisite number of bytes, but don't want to hold the UI thread while I do that. As far as I know, there is no such threshold for ReadAsync
to delay returning. This would be very helpful.
I have implemented the following as a workaround, but it doesn't feel like a good solution to me. Looping around the asynchronous method feels like I'm just writing a busy-waiting loop to wait for the input buffer to fill, and I might as well use the synchronous version. While I know the await
probably does return control to the caller to some extent between each byte arriving, this is not a question about profiling code for speed and efficiency, but rather about what the right coding pattern is and if I am taking advantage of asynchronous programming or handicapping it.
byte[] header = new byte[3];
int bytesRead = 0;
while (bytesRead < header.Length)
{
bytesRead += await this.serialPort.BaseStream.ReadAsync(header, bytesRead, header.Length-bytesRead);
}
// similarly for byte[] data...