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)
Nice Work Bro
LikeLike
Thanks Solom š
LikeLike
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!!
LikeLike
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
———————
LikeLike
Can you show me how to use the data in the main thread?
Im getting bogus data after copyto() the byte[] to main thread.
LikeLike
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 š
LikeLike
Hey, can you explain how to actually grab the data from your serial communication class? What do we call to have the transmitted data?
Thanks!
LikeLike
Figured it out!
In the receive handler: e.Response(); contains the data.
LikeLike
What license have you released this under?
LikeLike
it’s free to use, just put text credit for me.
LikeLike
hello RoofMan, how can i display the received data in a richtextbox??
LikeLike
Convert the bytes array into string
This link will help
http://stackoverflow.com/questions/11654562/how-convert-byte-array-to-string
LikeLike
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?
LikeLike
This library is your solution for realtime connection
LikeLike
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 ?
LikeLike
In fact I didn’t test the maximum data-transfer rate but I will check it and tell you results
LikeLike
Hello Roofman
It is really thanks for the test.
However would you let me know what was your maximum speed when you use for your project?
LikeLike
12.1 kb/s for my uav telemetry but i think the lib can do more with enhancement.
LikeLike
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
LikeLike
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.
LikeLike
As you like, I built a Ground station using this class and it’s realtime without any lag and load on cpu
LikeLike
Very nice job Ahmed, thank you!!! I works fine on VS2012 but when I run it on VS2010, do not read from serial port.
LikeLike
I developed it on VS2010 :D, Check again and make sure you are using .NET 4
LikeLike
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
LikeLike
use .NET 4 not client profile use the full framework
LikeLike
I used .NET 4 full framework, but on VS2010 not run š¦
LikeLike
Send me a screenshot
LikeLike
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
LikeLike
Ignore question… I figure it out š š
LikeLike
hi ahmed
how to clear the buffer?
i have data repeat
LikeLike
What buffer. Can you show me sample of your problem
LikeLike
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
LikeLike
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
LikeLike
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?
LikeLike
Max speed is 12kb on the high bauds
LikeLike
Hi, have you found the way to deal with a 921kps serial interface in c# ? regards, Pablo
LikeLike
Hi David, have you found the way to deal with a 921kps serial interface in c# ? regards, Pablo
LikeLike
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?
LikeLike
Create a global Byte list and when your receive bytes append to the list and when list count >=256 process the data.
LikeLike
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
LikeLike
Hi,,can you help me how to use this script same as readline function ?
LikeLike
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.
LikeLike
very nice;
but please help me how read data from serial port on this way, such as readLine() or nay other.
https://polldaddy.com/js/rating/rating.js
LikeLike
nice work bro. it is 3 times faster than normal library
LikeLike
I have one data package 40 bytes long coming once every ms. will this work
LikeLike
yes it gonna work.
LikeLike
Just a heads up running “Diagnostics.Debug…” within SerialReceiving will eat your CPU. On my MAC +- 10% constantly.
LikeLike
How to handle multiple serial ports
LikeLike
Create Several Classes From The Serial Class with Different Port Configuration and it should work normally.
LikeLike
I realize this has been our there for awhile, and thank-you for the nice library!!! This has helped me a ton. I do have a question, it seems that the receive buffer only receives 512 bytes before you need to read it, is there away to increase that? Maybe to 1000?
Thanks again for the awesome library!
Brandon
LikeLike
You mean you need to read 1000 Byte per on read ?!
LikeLike
Yes, I do need to read that many bytes. Is that possible?
Thank you!
LikeLike
your library saved my job reading video timecode from 24 up to 60 frames per second. the standard c# library is far too slow to do this without timecode gaps. thank you very much!
LikeLike
Hello RoofMan,
If the serial connection is interrupted, the program crashes. Is there a way to catch this error?
Thank you for support, Micha
LikeLike
Can you record screen while this case happen so i can support
LikeLike
iam using serialport control in application and sending 24 bytes for every 2.5 milliseconds to board and reciveing 104 bytes from board using reciving handler in gui but unable receive total bytes in gui.iam miising bytes in gui.
LikeLike
Iam using the baudrate of 2mbps
LikeLike
You need a protocol layer so you could build the message from multiple batches of bytes you receive.
Simple Protocol Layer or Complex Layer as you like.
For example Protocol
https://mavlink.io/en/
LikeLike