Zack
Zack

Reputation: 19

Serial Port Data Received Event Handler Reliability

I am using the Serial Port functionality in C# to communicate with a piece of hardware. Everything writes fine to the serial port, and the serial port is always connected.

For some reason the Serial Port Data Received Handler doesn't always read data coming up (every 1 out of 8 times it fails to read anything or call the event function itself). Everything is fine on the other side. I am only receiving one letter from the serial port which is 1, 2, 3, etc

Here is my code:

Serial Setup:

    //Create new serial port
    SerialPort SerPort = new SerialPort("COM4");

    private void SetupSerial()
    {
        SerPort.BaudRate = 9600;
        SerPort.Parity = Parity.None;
        SerPort.StopBits = StopBits.One;
        SerPort.DataBits = 8;
        SerPort.Handshake = Handshake.None;
        SerPort.ReadTimeout = 4000;
        SerPort.WriteTimeout = 6000;
        SerPort.Open();
        SerPort.DataReceived += new SerialDataReceivedEventHandler(HandleSerialData);

        lblStatus.Text = "Successfully connected to COM port with no errors!";

    }

My Write to Serial function:

       private void WriteToSerial( string data )
    {
        byte[] MyMessage = Encoding.UTF8.GetBytes(data);
        SerPort.Write(MyMessage, 0, MyMessage.Length);

        string time = "[" + DateTime.Now.ToString("HH:mm") + "]";

        bool debug = chkDebug.Checked;
        if (debug ) f.DebugText = time + " Wrote bytes to serial: " + data;
    }

My Recieve event function:

    //Called everytime serial data is recieved
    private void HandleSerialData(object sender, SerialDataReceivedEventArgs e)
    {
        try
        {
            //Store recieved data in variable
            SerialPort sp = (SerialPort)sender;
            string data = sp.ReadExisting().ToString();

            bool debug = chkDebug.Checked;

            string time = "[" + DateTime.Now.ToString("HH:mm") + "]";
            if( debug ) f.DebugText = time + " Recieved serial data: " + data;

            switch ( data )
            {
                case "1":
                //If Battery is already on
                if( Battery1[0] == "ON")
                {
                    Battery1[0] = "OFF"; //ON or OFF
                    Battery1[2] = DateTime.Now.ToString("h:mm tt"); //End time
                    WriteLogFile("1");
                    lblST1.Text = "n/a";
                    lblET1.Text = "n/a";
                    if (debug) f.DebugText = time + " Battery 1 testing switched OFF.";
                }
                else
                {
                    Battery1[0] = "ON"; //ON or OFF
                    Battery1[1] = DateTime.Now.ToString("h:mm tt"); //Start time
                    Battery1[5] = DateTime.Now.ToString("d/MM/yyyy"); //Start date
                    plcRespond = true;
                    lblST1.Text = Battery1[1];
                        if (debug) f.DebugText = time + " Battery 1 testing switched ON.";
                }
                break;

                case "2":
                //If Battery is already on
                if (Battery2[0] == "ON")
                {
                    Battery2[0] = "OFF";
                    Battery2[2] = DateTime.Now.ToString("h:mm tt"); //End time
                    WriteLogFile("2");
                    lblST2.Text = "n/a";
                    lblET2.Text = "n/a";
                        if (debug) f.DebugText = time + " Battery 2 testing switched OFF.";
                }
                else
                {
                    Battery2[0] = "ON"; //ON or OFF
                    Battery2[1] = DateTime.Now.ToString("h:mm tt"); //Start time
                    Battery2[5] = DateTime.Now.ToString("d/MM/yyyy"); //Start date
                    plcRespond = true;
                    lblST2.Text = Battery2[1];
                        if (debug) f.DebugText = time + " Battery 2 testing switched ON.";
                }
                break;

                case "3":
                //If Battery is already on
                if (Battery3[0] == "ON")
                {
                    Battery3[0] = "OFF"; //ON or OFF
                    Battery3[2] = DateTime.Now.ToString("h:mm tt"); //End time
                    WriteLogFile("3");
                    lblST3.Text = "n/a";
                    lblET3.Text = "n/a";
                        if (debug) f.DebugText = time + " Battery 3 testing switched OFF.";
                }
                else
                {
                    Battery3[0] = "ON"; //ON or OFF
                    Battery3[1] = DateTime.Now.ToString("h:mm tt"); //Start time
                    Battery3[5] = DateTime.Now.ToString("d/MM/yyyy"); //Start date
                    plcRespond = true;
                    lblST3.Text = Battery3[1];
                        if (debug) f.DebugText = time + " Battery 3 testing switched ON.";
                }
                break;

                case "4":
                //If Battery is already on
                if (Battery4[0] == "ON")
                {
                    Battery4[0] = "OFF"; //ON or OFF
                    Battery4[2] = DateTime.Now.ToString("h:mm tt"); //End time
                    WriteLogFile("4");
                    lblST4.Text = "n/a";
                    lblET4.Text = "n/a";
                        if (debug) f.DebugText = time + " Battery 4 testing switched OFF.";
                }
                else
                {
                    Battery4[0] = "ON"; //ON or OFF
                    Battery4[1] = DateTime.Now.ToString("h:mm tt"); //Start time
                    Battery4[5] = DateTime.Now.ToString("d/MM/yyyy"); //Start date
                    plcRespond = true;
                    lblST4.Text = Battery4[1];
                        if (debug) f.DebugText = time + " Battery 4 testing switched ON.";
                }
                break;

                case "5":
                //If Battery is already on
                if (Battery5[0] == "ON")
                {
                    Battery5[0] = "OFF"; //ON or OFF
                    Battery5[2] = DateTime.Now.ToString("h:mm tt"); //End time
                    WriteLogFile("5");
                    lblST5.Text = "n/a";
                    lblET5.Text = "n/a";
                        if (debug) f.DebugText = time + " Battery 5 testing switched OFF.";
                    }
                else
                {
                    Battery5[0] = "ON"; //ON or OFF
                    Battery5[1] = DateTime.Now.ToString("h:mm tt"); //Start time
                    Battery5[5] = DateTime.Now.ToString("d/MM/yyyy"); //Start date
                    plcRespond = true;
                    lblST5.Text = Battery5[1];
                        if (debug) f.DebugText = time + " Battery 5 testing switched ON.";
                }
                break;

                case "6":
                //If Battery is already on
                if (Battery6[0] == "ON")
                {
                    Battery6[0] = "OFF"; //ON or OFF
                    Battery6[2] = DateTime.Now.ToString("h:mm tt"); //End time
                    WriteLogFile("6");
                    lblST6.Text = "n/a";
                    lblET6.Text = "n/a";
                        if (debug) f.DebugText = time + " Battery 6 testing switched OFF.";
                }
                else
                {
                    Battery6[0] = "ON"; //ON or OFF
                    Battery6[1] = DateTime.Now.ToString("h:mm tt"); //Start time
                    Battery6[5] = DateTime.Now.ToString("d/MM/yyyy"); //Start date
                    plcRespond = true;
                    lblST6.Text = Battery6[1];
                        if (debug) f.DebugText = time + " Battery 6 testing switched ON.";
                }
                break;
            }

            SerPort.DiscardInBuffer();
            SerPort.DiscardOutBuffer();

        }
        catch (Exception ex)
        {
            MessageBox.Show("Error recieving COM data! " + ex.Message);
        }
    }

Is there a better way of reading serial data not using the ReadExisting? Or using a more reliable function?

Upvotes: 0

Views: 1317

Answers (1)

MikeS159
MikeS159

Reputation: 1974

I have had problem in the past with ReadExisting. I don't know what happens in ReadExisting if more data arrives while the buffer is being read.

In serial port even handlers I use the following code. Because it determines the length to read first, new data arriving will be read during the next function call so the buffer can be emptied at the rate data is sent.

private void HandleSerialData(object sender, SerialDataReceivedEventArgs e)
{
    int lengthToRead = sp.BytesToRead;
    byte[] rxBytes = new byte[lengthToRead];
    sp.Read(rxBytes, 0, lengthToRead);
    functionThatInterpratesData(rxBytes);
}

This also has the benefit of being re-usable because you convert the byte array to a string or however you have encoded it separately.

I would create a function to convert you byte array to a string (lots of examples on SO) and another one to handle the case statement.

Upvotes: 2

Related Questions