radensb
radensb

Reputation: 694

Serial Port Communication Delay using C#

I am trying to write a C# application that reads UART data at 115200bps. The data is in the format:

ID: XXX Data: XX XX XX XX XX XX XX XX
ID: XXX Data: XX XX XX XX XX XX XX XX
ID: XXX Data: XX XX XX XX XX XX XX XX

where the X's represent hex values.

Each transmission ends in a newline character ('\n'). Below is the code from my C# application. It simply reads the data line by line, parses out the ID and the Data fields into variables, then inserts the data into a dataGridView object. If the ID entry does not exist in the table, it and its data are added. If the ID entry already exists (is a repeat), then the existing data for the repeated ID entry is updated with the new data. This lets me see how the data in the listed ID's are changing.

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            serialPort.PortName = "COM11";
            serialPort.BaudRate = 115200;
            serialPort.Open();
            serialPort.DiscardOutBuffer();
            serialPort.DiscardInBuffer();

        }

        private delegate void SetTextDeleg(string text);
        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string CAN_tx = serialPort.ReadLine();
            this.BeginInvoke(new SetTextDeleg(processCAN), new object[] { CAN_tx });
        }

        void processCAN(string CAN_tx)
        {
            CANout_txtbox.Text = CAN_tx;
            Match match = Regex.Match(CAN_tx, @"^ID:\s([A-F0-9]+)\s+Data:\s([^\r]+)", RegexOptions.IgnoreCase);
            if (!match.Success) return;
            string pid = match.Groups[1].Value.Trim();
            string data = match.Groups[2].Value.Trim();
            string raw = pid + " " + data;

            string[] row = raw.Split(' ');

            int rowIndex = -1;

            try
            {
                DataGridViewRow matchRow = dataTable.Rows
                    .Cast<DataGridViewRow>()
                    .Where(r => r.Cells["PID"].Value.ToString().Equals(match.Groups[1].Value))
                    .First();

                rowIndex = matchRow.Index;
            }
            catch { }

            if (rowIndex != -1)
            {
                dataTable.Rows[rowIndex].SetValues(row);
            }
            else
            {
                dataTable.Rows.Add(row);
            }
        }
    } 
}

The program works, however, it seems that there is a problem with the serial communication performance. When I view the data stream in a console, i can see several hundred ID's being sent per second. (The ID's repeat every 10, 20, 50, 100, 110 ms, depending on the ID) When I view the data in the C# application, I see maybe 50 ID's per second. This results in a huge delay between the time the data is sent to the C# application and the time the data is updated in the C# application.

Is there some way to set priority to the COM port I am using? Or is there deeper issues here? I tried lowering the serial buffer, changing timeouts, and number of bytes needed to trigger the data received event, but nothing has made an impact.

I have already started a new approach in Python as I was able to display data in near real time, however, I would like to understand what is happening in my C# application that is preventing the performance I need.

Thanks!

Upvotes: 0

Views: 4311

Answers (2)

Inspired
Inspired

Reputation: 46

This might be solved by using background workers to process the data and main just for doing datagrid [GUI] updates? It could be just me, but the majority of my data processing lives in bw-ers these days..

Edit: Another thought, depending on how many "rows" of data your are expecting, an idea might be to store the info in a hashtable (very fast to search) or datatable? Does the "delay" get worse when more elements are added, is it cumulative?

Edit2: A good tutorial on how to correctly use background workers [Should you decide to use them!]

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941327

I see maybe 50 ID's per second.

That's not physically possible, your eyes are not good enough to see changes at that rate. You fooled yourself with the console mode program, you inferred hundreds of changes per second from the rate at which the lines scrolled across the console window. Never actually reading any of them of course.

That physiological effect stops working when you update rows in the grid. Now you are doing the same thing that the movie projector in the cinema does. It updates frames at 24 per second. Or the television you watched a show on, it updates frames at 25 or 30 per second. You cannot see the individual frames, they change too fast for your eye to observe. Albeit that 24 fps is on the low end, the original rate before digital projection became common, the flicker tended to be noticeable.

Human eyes conk out at around 20 updates per second, go any faster and it just turns into a blur. Which is otherwise a Good Thing, it helps the broadcasters and theater exploiters from spending a lot of money on expensive equipment, the kind that will eat a roll of film in a manner of minutes.

Long story short, you are writing an unusable program. Your user will look at the wildly blinking numbers and quickly lose interest. Turning the firehose of data into useful information is something you'll have to think about, nothing very obvious jumps to mind here.

Upvotes: 4

Related Questions