I'm trying to make an application with GUI (WinForms) that reads data from an FTDI chip via USB and doesn't cause the UI to freeze while reading.
The application window is no longer responsive. The buttons I added to the window don't work, nor does minimize, maximize, close with a cross.... nothing related to the window works. But I can see in the application debugging window in Visual Studio that data is being received.
The data reading is based on an Event from the FTDI driver: ftHandle.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);
.
It would be appropriate for the reception of this data to work in a separate thread, so as not to block the GUI. I have read that in 90% of cases the best way to handle threads is Tasks. Unfortunately, the following code snippet reads the data, but the UI blocks during this time. How to solve this problem?
This code is executed once, right after the FTDI is initialized to work:
var receivedDataEvent = new AutoResetEvent(false);
ftHandle.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);
// Create a new task to receive data
Task dataReceiveTask = new Task(async () =>
{
while (true)
{
// Wait for the FT_EVENT_RXCHAR event
receivedDataEvent.WaitOne();
await Task.Run(() =>
{
ReadDataAvailableInFtdiBuffer();
});
}
});
// Start the data receive task
dataReceiveTask.Start();
And the ReadDataAvailableInFtdiBuffer();
is:
void ReadDataAvailableInFtdiBuffer()
{
ftStatus = ftHandle.GetRxBytesAvailable(ref numBytesAvailable);
if (numBytesAvailable < 1)
return;
System.Diagnostics.Debug.WriteLine(ftStatus + " bytes available: " + numBytesAvailable.ToString());
byte[] bytes = new byte[numBytesAvailable];
UInt32 numBytesRead = 0;
ftHandle.Read(bytes, numBytesAvailable, ref numBytesRead);
// --------------------------------------------------------------------------------------------
// Calling Received Data Event with passing data to the event subscriber (USB)
// OnFtdiBytesReceived?.Invoke(this, new FtdiBytesReceivedEventArgs(bytes, numBytesAvailable));
// --------------------------------------------------------------------------------------------
}
EDIT: using Task.Run as suggested in comments:
var receivedDataEvent = new AutoResetEvent(false);
ftHandle.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);
// Create a new task to receive data
Task dataReceiveTask = Task.Run(() =>
{
while (true)
{
// Wait for the FT_EVENT_RXCHAR event
receivedDataEvent.WaitOne();
ReadDataAvailableInFtdiBuffer();
}
});
But the UI behaviour is the same.