Fast Serial Communication For C# Real-Time Applications

Fast Serial Communication For C# Real-Time Applications

While I’m working in AeroXtreme MAV Researching Project, i faced a serious problem in the serial communication in .NET C#. The standard C# serial component is too slow to handle fast serial communication for real-time applications. The MAV Main Computer send data over serial communication in high frequency and send a lot of data. When I used the standard C# serial library “Receiving Event” a huge lag of communication appeared and the buffers is jammed due to the high frequency of communication. After a lot of testing and debugging i found that the serial communication using the standard library will fail in such application so i tried to develop a Fast Serial Library to fulfill my requirement of real-time communication. My Library solve this problem and it can work with high frequency communication without any overhead on the processor due to the frequency control technique.

/* This AX-Fast Serial Library
   Developer: Ahmed Mubarak - RoofMan

   This Library Provide The Fastest & Efficient Serial Communication
   Over The Standard C# Serial Component
*/

using System;
using System.IO.Ports;
using System.Threading;
using Diagnostics = System.Diagnostics;

namespace RTSerialCom
{
    public class DataStreamEventArgs : EventArgs
    {
        #region Defines
        private byte[] _bytes;
        #endregion

        #region Constructors
        public DataStreamEventArgs(byte[] bytes)
        {
           _bytes = bytes;
        }
        #endregion

        #region Properties
        public byte[] Response
        {
            get { return _bytes; }
        }
        #endregion
    }

    public class SerialClient : IDisposable
    {
        #region Defines
        private string _port;
        private int _baudRate;
        private SerialPort _serialPort;
        private Thread serThread;
        private double _PacketsRate;
        private DateTime _lastReceive;
        /*The Critical Frequency of Communication to Avoid Any Lag*/
        private const int freqCriticalLimit = 20;
        #endregion

        #region Constructors
        public SerialClient(string port)
        {
            _port = port;
            _baudRate = 9600;
            _lastReceive = DateTime.MinValue;

            serThread = new Thread(new ThreadStart(SerialReceiving));
            serThread.Priority = ThreadPriority.Normal;
            serThread.Name = "SerialHandle" + serThread.ManagedThreadId;
        }
        public SerialClient(string Port, int baudRate)
            : this(Port)
        {
            _baudRate = baudRate;
        }
        #endregion

        #region Custom Events
        public event EventHandler<DataStreamEventArgs> OnReceiving;
        #endregion

        #region Properties
        public string Port
        {
            get { return _port; }
        }
        public int BaudRate
        {
            get { return _baudRate; }
        }
        public string ConnectionString
        {
            get
            {
                return String.Format("[Serial] Port: {0} | Baudrate: {1}",
                    _serialPort.PortName, _serialPort.BaudRate.ToString());
            }
        }
        #endregion

        #region Methods
        #region Port Control
        public bool OpenConn()
        {
            try
            {
                if (_serialPort == null)
                    _serialPort = new SerialPort(_port, _baudRate, Parity.None);

                if (!_serialPort.IsOpen)
                {
                    _serialPort.ReadTimeout = -1;
                    _serialPort.WriteTimeout = -1;

                    _serialPort.Open();

                    if (_serialPort.IsOpen)
                        serThread.Start(); /*Start The Communication Thread*/
                }
            }
            catch (Exception ex)
            {
                return false;
            }

            return true;
        }
        public bool OpenConn(string port, int baudRate)
        {
            _port = port;
            _baudRate = baudRate;

            return OpenConn();
        }
        public void CloseConn()
        {
            if (_serialPort != null && _serialPort.IsOpen)
            {
                serThread.Abort();

                if (serThread.ThreadState == ThreadState.Aborted)
                    _serialPort.Close();
            }
        }
        public bool ResetConn()
        {
            CloseConn();
            return OpenConn();
        }
        #endregion
        #region Transmit/Receive
        public void Transmit(byte[] packet)
        {
            _serialPort.Write(packet, 0, packet.Length);
        }
        public int Receive(byte[] bytes, int offset, int count)
        {
            int readBytes = 0;

            if (count > 0)
            {
                readBytes = _serialPort.Read(bytes, offset, count);
            }

            return readBytes;
        }
        #endregion
        #region IDisposable Methods
        public void Dispose()
        {
            CloseConn();

            if (_serialPort != null)
            {
                _serialPort.Dispose();
                _serialPort = null;
            }
        }
        #endregion
        #endregion

        #region Threading Loops
        private void SerialReceiving()
        {
            while (true)
            {
                int count = _serialPort.BytesToRead;

                /*Get Sleep Inteval*/
                TimeSpan tmpInterval = (DateTime.Now - _lastReceive);

                /*Form The Packet in The Buffer*/
                byte[] buf = new byte[count];
                int readBytes = Receive(buf, 0, count);

                if (readBytes > 0)
                {
                    OnSerialReceiving(buf);
                }

                #region Frequency Control
                _PacketsRate = ((_PacketsRate + readBytes) / 2);

                _lastReceive = DateTime.Now;

                if ((double)(readBytes + _serialPort.BytesToRead) / 2 <= _PacketsRate)
                {
                    if (tmpInterval.Milliseconds > 0)
                        Thread.Sleep(tmpInterval.Milliseconds > freqCriticalLimit ? freqCriticalLimit : tmpInterval.Milliseconds);

                    /*Testing Threading Model*/
                    Diagnostics.Debug.Write(tmpInterval.Milliseconds.ToString());
                    Diagnostics.Debug.Write(" - ");
                    Diagnostics.Debug.Write(readBytes.ToString());
                    Diagnostics.Debug.Write("\r\n");
                }
                #endregion
            }

        }
        #endregion

        #region Custom Events Invoke Functions
        private void OnSerialReceiving(byte[] res)
        {
            if (OnReceiving != null)
            {
                OnReceiving(this, new DataStreamEventArgs(res));
            }
        }
        #endregion
    }
}

I wrote a sample project that will help you understand how to use it (Download Sample)

Advertisements

42 thoughts on “Fast Serial Communication For C# Real-Time Applications

  1. hi Ahmed
    i have an application with the following:
    baudrate 115200
    messages are 400bytes long 100ms apart from each other
    and i need to acknowledge each message i receive,
    will it works?
    how does the frequency control will help me here??
    i actually try it but did not receive the whole bytes of the message!!

    1. Use This Config
      Frequency Control = 1000Hz = 1ms -> Baudrate = 115200 Baud – Packet Len = 400 Byte

      but the Library i shared used to improve the speed or reception and transmission, and the frequency control used to reduce the CPU overhead only but sometime you can use it to have more processor time to make the communication smoother but that’s mean processor overhead.

      I prefer to develop upper layer (Protocol layer) to handle the received bytes and to make sure the message is complete and correct, and in this layer too you have to develop a technique of handshaking to use it in acknowledgement.

      Simple Architecture
      ———————

      • App Layer -> Your Application
      • Protocol Layer -> Process The Messages and Form it and do some CRC on it if possible, to make sure the message is correct and complete
      • Serial Layer -> Provide Real-time Communication with the other clients with very small delay for real-time applications
  2. Can you show me how to use the data in the main thread?
    Im getting bogus data after copyto() the byte[] to main thread.

    1. You have 2 methods to this:
      Timers like i done in the example or using Delegates to update the GUI.

      If you can’t solve the problem send me on my private email a sample from your problem to send you the solution in the same sample you sent ๐Ÿ™‚

  3. Would you recommend if I used this library to handle received data from serial? I’m building an electronic drum and I’m using a software app as the “brain” Can you suggest any other thing to make it work?

  4. Hello RoofMan
    many thanks to share this great library !!
    I am trying to receive from serial using this
    however the data over 115200 baud is missing sometimes.
    What is your maximum data transfer rate ?

  5. Hi,

    Thanks a lot for the code shared. I am quite new to C#, so sorry if I sound a bit silly.
    As of now I am using serialPort1.ReadLine() in the System.IO.Ports namespace. The serial will be printing one set of data is one line and I have to get the line into the program as string. Can you tell me which function to call in your class for this.

    Thanks
    Harish

  6. It’s fake… I’m searching for really fast serial communication to delete lags after receiving data.
    This solution is not faster at all. Lag is 15ms, still… You changed way to receive data bytes.

      1. hi Ahmed, thanks for the reply. Iยดm using .NET 4 Client Profile in both but on VS2010 do not run. I tried to change the differents Target frameworks but still does not run

  7. Hi Ahmed!

    I’m using VS2010 and .net framewotk 4.0. and reception is working. But I can’t figure out how to send data with your library: Would you help me please ?

    Regards !

    Mladen

      1. i add this code to reciveHandler
        str = System.Text.Encoding.Default.GetString(e.Response);
        and in timer add this
        File.AppendAllText(@”J:\test1.txt”, str);

        for test i send data ( 1 to 12000)from ARM
        but in my tes1 file my data repeated
        for example
        12341234567891056789105678910111213……12000
        1234
        repeated
        and
        5678910

      2. Debug it. The Lib don’t return duplication.

        Only new data from the buffer. Check your handling code.

        I’m sure it’s your code. Because alot of people use it like me without any problem.

        If you want extra support. Send me your code privately on my mail

        Roofman2008@gmail.com

  8. I have to acheive the speed of 921,600bps with serial interface in c#. So, I have a question. What is the maximum speed of serial communication if above source code is applied?

  9. Hey:
    First of all, thank you very much for this library, I am planning to use this to make a GUI to one project in which I need to have a great receiving velocity, this must be very silly question but this is my first time with threading.
    I am having a hard time to traduce my project from the Serial Class library to yours. I am sending from my MCU 258 bytes to the PC, and I am waiting for this 258 bytes to get into the serial port, and then proceed with the analysis. I am currently using the property of e.Respose.Length to get the number of bytes in my serial buffer, and only if e.Respose.Length >= 258, the program read the data with your serialclient.Receive(Array, offset, count).
    But the problem here is that I cannot receive the 258 bytes of data, and the event doesn’t occur anymore…
    The question here is how can I wait for data chunk to get to my serial port?

      1. First of all, thanks for the advice. I did what you recommend me yesterday and it worked quite good, but one thing that seems strange to me, is that: the time between I send the command to the MCU to send me the data until I receive the data (reaction time) is greater than the time from the serial class library.
        How can I know the reaction time of serial events? I am using the stopwatch library, from the moment I send the data request to the moment I receive all the data I am needing.
        In fact the serial class has an average time of reaction of 25 ms, but your library in the way I am using it is giving me an average time of reaction of 40 ms.
        this is the code of the receive handler:
        private void receiveHandler(object sender, DataStreamEventArgs e)
        {
        readBuf.AddRange(e.Response.ToList());
        if (readBuf.Count >= readBuffer.Length)
        {
        timer_count2 = swatch.ElapsedMilliseconds;
        this.Invoke(new EventHandler(ChangeToArr));
        }
        }
        As you can see is simple and it works in my code, and although the reaction time is almost invariable in compared to the time of reaction of the serial class, the thing is that the time of reaction is slow.
        I don’t know if I am missing something, I would appreciate any advice that you can bring me.
        Martin

  10. When transmitting if the receiving application is not successfully picking up – the SerialClient locks up. Placing a real timeout value fixes the issue. I added properties for IsOpen and also for transmit and receive text.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s