I'm creating an application which communicates with the device via FT2232H USB/RS232 converter. For communication I'm using FTD2XX_NET.dll library from FTDI website.
I'm using two threads:
I've got a problem when I'm trying to write any data to the device while the receiver's thread is running. The main thread simply hangs up on ftdiDevice.Write function.
I tried to synchronize both threads so that only one thread can use Read/Write function at the same time, but it didn't help.
Below code responsible for the communication. Note that following functions are methods of FtdiPort class.
Receiver's thread
private void receiverLoop()
{
if (this.DataReceivedHandler == null)
{
throw new BackendException("dataReceived delegate is not set");
}
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
byte[] readBytes = new byte[this.ReadBufferSize];
while (true)
{
lock (FtdiPort.threadLocker)
{
UInt32 numBytesRead = 0;
ftStatus = ftdiDevice.Read(readBytes, this.ReadBufferSize, ref numBytesRead);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
this.DataReceivedHandler(readBytes, numBytesRead);
}
else
{
Trace.WriteLine(String.Format("Couldn't read data from ftdi: status {0}", ftStatus));
Thread.Sleep(10);
}
}
Thread.Sleep(this.RXThreadDelay);
}
}
Write function called from main thread
public void Write(byte[] data, int length)
{
if (this.IsOpened)
{
uint i = 0;
lock (FtdiPort.threadLocker)
{
this.ftdiDevice.Write(data, length, ref i);
}
Thread.Sleep(1);
if (i != (int)length)
{
throw new BackendException("Couldnt send all data");
}
}
else
{
throw new BackendException("Port is closed");
}
}
Object used to synchronize two threads
static Object threadLocker = new Object();
Method that starts the receiver's thread
private void startReceiver()
{
if (this.DataReceivedHandler == null)
{
return;
}
if (this.IsOpened == false)
{
throw new BackendException("Trying to start listening for raw data while disconnected");
}
this.receiverThread = new Thread(this.receiverLoop);
//this.receiverThread.Name = "protocolListener";
this.receiverThread.IsBackground = true;
this.receiverThread.Start();
}
The ftdiDevice.Write function doesn't hang up if I comment following line:
ftStatus = ftdiDevice.Read(readBytes, this.ReadBufferSize, ref numBytesRead);
A few things:
Check to see if your Read call is blocking. If so, you might not be able to call Write while the Read is blocking waiting for a response. Your API documentation may have more details on this.
Some APIs do not support multiple threads very well, even when synchronizing access. If that's the case here, you can use a design where you delegate your Write commands to your comm thread. When I've used this pattern in the past, I typically queue up some sort of Command class containing the information I wish to write, and either use a threading Signal class to allow my calling 'command' methods to block or provide some sort of asynchronous notification.
Checking out the API, it looks to me that the driver is capable of emulating a COM port. I see the GetComPort() method returning a "COMx" string. That makes it pretty likely that you can use the System.IO.Ports.SerialPort class. Which already does what your wrapper is trying to do, it supports a DataReceived event. Worth a shot.
An alternative is to use the event notification mechanism from FTDI, this way you don't need a blocking thread to read out data:
I've found more detailed API documentation. Indeed the ftdiDevice.read function is blocking unless you set the readTimeout value other then 0. Setting this timeout value solved the problem.
Thanks for your quick response.
Regards