I am trying to use the SerialPort class in .net.
I've opted to keep my service async, so I am using the async-methods on SerialPort.BaseStream
.
In my async method, I write a byte[] to the serial port, then start reading until I haven't received any more data in n milliseconds, and return that result.
The problem is, however, that I seem to miss the first byte in all replies other than the very first reply after opening the serial port.
If I close the port after every response (Read), and open it again before doing a new request (Write), the first byte is not missing. This, however, often results in a "Access to the port 'COM4' is denied."
exception, if I try to open the port too soon after closing. It also seems very unnecessary to open/close for every write/read.
This is basically what my method looks like:
private async Task<byte[]> SendRequestAsync(byte[] request)
{
// Write the request
await _serialPort.BaseStream.WriteAsync(request, 0, request.Length);
var buffer = new byte[BUFFER_SIZE];
bool receiveComplete = false;
var bytesRead = 0;
// Read from the serial port
do
{
var responseTask = _serialPort.BaseStream.ReadAsync(buffer, bytesRead, BUFFER_SIZE - bytesRead);
if (await Task.WhenAny(responseTask, Task.Delay(300)) == responseTask)
{
bytesRead += responseTask.Result;
}
else
receiveComplete = true;
} while (!receiveComplete);
var response = new byte[bytesRead];
Array.Copy(buffer, 0, response, 0, bytesRead);
return response;
}
Is there anything obviously wrong in the way I am doing this? Is there a smarter way to achieve the same asynchronously?
Just because you're not observing the last
ReadAsync()
doesn't mean it gets canceled, it's still running, which apparently manifests by it reading the first byte of the following message.What you should do is to cancel the last
ReadAsync()
by using aCancellationToken
. Note that there is a possible race between the timeout and the read, but I'm assuming that if the timeout elapsed, it's not possible for the read to complete without another write.The code would look like this:
Note that both the cause and the solution are my guesses, it's certainly possible that I'm wrong about one or both of them.