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.