+3  A: 

A few things:

  1. 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.

  2. 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.

Dan Bryant
A: 

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

mack369
+1  A: 

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.

Hans Passant
I've already tried to use SerialPort class, but I've found the problem described in http://stackoverflow.com/questions/924070/ and didn't find any workaround for that.
mack369
@mack: tip #4 here: http://blogs.msdn.com/bclteam/archive/2006/10/10/Top-5-SerialPort-Tips-_5B00_Kim-Hamilton_5D00_.aspx
Hans Passant
nice tip, but I cannot use SerialPort class anyway. I checked the maximum baud rate and it is below my expectation - about 2Mb/s. With direct access to the hardware I can have even 4.5Mb/s
mack369
A: 

An alternative is to use the event notification mechanism from FTDI, this way you don't need a blocking thread to read out data:

public FTDISample()
{
    private AutoResetEvent receivedDataEvent;
    private BackgroundWorker dataReceivedHandler;
    private FTDI ftdi;

    public FTDISample(string serialNumber){
        ftdi = new FTDI();
        FTDI.FT_STATUS status = ftdi.OpenBySerialNumber(serialNumber);
        receivedDataEvent = new AutoResetEvent(false);
        status = mFTDI.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);
        dataReceivedHandler = new BackgroundWorker();
        dataReceivedHandler.DoWork += ReadData;
        if (!dataReceivedHandler.IsBusy)
        {
            dataReceivedHandler.RunWorkerAsync();
        }
    }

    private void ReadData(object pSender, DoWorkEventArgs pEventArgs)
    {
        UInt32 nrOfBytesAvailable = 0;
        while (true)
        {
            // wait until event is fired
            this.receivedDataEvent.WaitOne();

            // try to recieve data now
            FTDI.FT_STATUS status = ftdi.GetRxBytesAvailable(ref nrOfBytesAvailable);
            if (status != FTDI.FT_STATUS.FT_OK)
            {
                break;
            }
            if (nrOfBytesAvailable > 0)
            {
                byte[] readData = new byte[nrOfBytesAvailable];
                UInt32 numBytesRead = 0;
                status = mFTDI.Read(readData, nrOfBytesAvailable, ref numBytesRead);

                // invoke your own event handler for data received...
                //InvokeCharacterReceivedEvent(fParsedData);
            }
        }
    }

    public bool Write(string data)
    {
        UInt32 numBytesWritten = 0;
        ASCIIEncoding enconding = new ASCIIEncoding();
        byte[] bytes = enconding.GetBytes(data);
        FTDI.FT_STATUS status = ftdi.Write(bytes, bytes.Length, ref numBytesWritten);
        if (status != FTDI.FT_STATUS.FT_OK)
        {
            Debug.WriteLine("FTDI Write Status ERROR: " + status);
            return false;
        }
        if (numBytesWritten < data.Length)
        {
            Debug.WriteLine("FTDI Write Length ERROR: " + status + " length " + data.Length +
                            " written " + numBytesWritten);
            return false;
        }
        return true;
    }
Rogier