FTDI芯片C#编程 - 如何读取所有缓冲区?

时间:2013-06-26 12:12:33

标签: c# serial-port buffer ftdi

我目前正在开发一个使用FTDI芯片的项目。

我正在使用C#编程,我在FTDI网站上尝试了examples之一(带有数据环回的第3个)。

代码正常运行,我可以编写“Hello world”并将其读回来。在这种情况下,我们知道我们期望从缓冲区返回多少数据:

// Perform loop back - make sure loop back connector is fitted to the device
// Write string data to the device
   string dataToWrite = "Hello world!";
   UInt32 numBytesWritten = 0;

// Note that the Write method is overloaded, so can write string or byte array data
   ftStatus = myFtdiDevice.Write(dataToWrite, dataToWrite.Length, ref numBytesWritten);

   if (ftStatus != FTDI.FT_STATUS.FT_OK)
   {
       // Wait for a key press
       Console.WriteLine("Failed to write to device (error " + ftStatus.ToString() + ")");
       Console.ReadKey();
       return;
   }

   // Check the amount of data available to read
   // In this case we know how much data we are expecting, 
   // so wait until we have all of the bytes we have sent.
   UInt32 numBytesAvailable = 0;
   do
   {
       ftStatus = myFtdiDevice.GetRxBytesAvailable(ref numBytesAvailable);

       if (ftStatus != FTDI.FT_STATUS.FT_OK)
       {
           // Wait for a key press
           Console.WriteLine("Failed to get number of bytes available to read (error " + ftStatus.ToString() + ")");
           Console.ReadKey();
           return;
       }
       Thread.Sleep(10);
    } while (numBytesAvailable < dataToWrite.Length);

    // Now that we have the amount of data we want available, read it
    string readData;
    UInt32 numBytesRead = 0;

    // Note that the Read method is overloaded, so can read string or byte array data
    ftStatus = myFtdiDevice.Read(out readData, numBytesAvailable, ref numBytesRead);

    if (ftStatus != FTDI.FT_STATUS.FT_OK)
    {
        // Wait for a key press
        Console.WriteLine("Failed to read data (error " + ftStatus.ToString() + ")");
        Console.ReadKey();
        return;
    }
    Console.WriteLine(readData);

但是,如果我想读取所有数据并且我没有预期从缓冲区返回多少数据呢?

由于

2 个答案:

答案 0 :(得分:3)

使用事件驱动的方法;

using System;
using System.Timers;

namespace Example
{
    public class Program
    {
        private Timer m_timer;
        private event EventHandler<EventArgs<string>> ReadingAvailable;

        protected virtual void OnReadingAvailable(string value)
        {
            EventHandler<EventArgs<string>> handler = ReadingAvailable;
            if (handler != null)
            {
                handler(this, new EventArgs<string>(value));
            }
        }

        public static void Main(string[] args)
        {
            var foo = new Program();
            foo.Initialise();

            Console.ReadLine();
        }

        private void Initialise()
        {
            ReadingAvailable += Program_ReadingAvailable;

            m_timer = new Timer {Interval = 1000};
            m_timer.Elapsed +=timer_Elapsed;
            m_timer.Enabled = true;
            m_timer.Start();

        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
             string readData;
             UInt32 numBytesRead = 0;
             // Note that the Read method is overloaded, so can read string or byte array data
             ftStatus = myFtdiDevice.Read(out readData, numBytesAvailable, ref numBytesRead);

            // add the condition checking here to validate that the readData in not empty.
            OnReadingAvailable(readData);
        }

        private void Program_ReadingAvailable(object sender, EventArgs<string> e)
        {
            string readData= e.Value;
            Console.WriteLine(readData);
        }
    }

    ///
    /// Helper class to parse argument in the EventArg
    public class EventArgs<T> : EventArgs
    {
        private readonly T m_value;

        protected EventArgs()
            : base()
        {
            m_value = default(T);
        }

        public EventArgs(T value)
        {
            m_value = value;
        }

        public T Value
        {
            get { return m_value; }
        }
    }
}

答案 1 :(得分:1)

使用事件驱动方法的另一个选择是使用FTDI库中的实际事件通知机制,它特别适合流式传输:

Task.Run(() => ReceiveLoop());

void ReceiveLoop()
{
    var receivedDataEvent = new AutoResetEvent(false);
    myFtdiDevice.SetEventNotification(FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);

    var cancellation = new CancellationTokenSource();  // should be declared in a broader scope
    while (!_cancellation.IsCancellationRequested)
    {
        receivedDataEvent.WaitOne();
        ReadAvailable();
    }
}

void ReadAvailable()
{
    uint rxBytesAvailable = 0;
    myFtdiDevice.GetRxBytesAvailable(ref rxBytesAvailable);
    if (rxBytesAvailable < 1)
        return;
    byte[] bytes = new byte[rxBytesAvailable];
    uint numBytesRead = 0;
    myFtdiDevice.Read(bytes, rxBytesAvailable, ref numBytesRead);
    if (rxBytesAvailable != numBytesRead)
        logger.Warn("something happened")
    DoSomething(bytes);
}