Link to home
Start Free TrialLog in
Avatar of ocaccy
ocaccyFlag for Japan

asked on

Clear the buffer in serial port comunication on C#

How to clear the buffer.

using System;
using System.IO;
using System.IO.Ports;
using System.Threading;

namespace NanoFX

{
    /// <summary> CommPort class creates a singleton instance
    /// of SerialPort (System.IO.Ports) </summary>
    /// <remarks> When ready, you open the port.
    ///   <code>
    ///   CommPort com = CommPort.Instance;
    ///   com.StatusChanged += OnStatusChanged;
    ///   com.DataReceived += OnDataReceived;
    ///   com.Open();
    ///   </code>
    ///   Notice that delegates are used to handle status and data events.
    ///   When settings are changed, you close and reopen the port.
    ///   <code>
    ///   CommPort com = CommPort.Instance;
    ///   com.Close();
    ///   com.PortName = "COM4";
    ///   com.Open();
    ///   </code>
    /// </remarks>
	public sealed class CommPort




    {
        SerialPort _serialPort;
		Thread _readThread;
		volatile bool _keepReading;





        //begin Singleton pattern
        static readonly CommPort instance = new CommPort();



		// Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static CommPort()






















        {











        }

        CommPort()
        {

			_serialPort = new SerialPort();
			_readThread = null;
			_keepReading = false;
		}


		public static CommPort Instance


        {
            get

            {
                return instance;


            }

        }
        //end Singleton pattern


		//begin Observer pattern
        public delegate void EventHandler(string param);
        public EventHandler StatusChanged;
        public EventHandler DataReceived;
        //end Observer pattern




		private void StartReading()
		{
			if (!_keepReading)
			{
				_keepReading = true;
				_readThread = new Thread(ReadPort);
				_readThread.Start();
			}
		}






		private void StopReading()
		{
			if (_keepReading)
			{
				_keepReading = false;
				_readThread.Join();	//block until exits
				_readThread = null;
			}
		}



		/// <summary> Get the data and pass it on. </summary>
		private void ReadPort()
		{
			while (_keepReading)
			{
				if (_serialPort.IsOpen)
				{
					byte[] readBuffer = new byte[_serialPort.ReadBufferSize + 1];
					try
					{
						// If there are bytes available on the serial port,
						// Read returns up to "count" bytes, but will not block (wait)
						// for the remaining bytes. If there are no bytes available
						// on the serial port, Read will block until at least one byte
						// is available on the port, up until the ReadTimeout milliseconds
						// have elapsed, at which time a TimeoutException will be thrown.
						int count = _serialPort.Read(readBuffer, 0, _serialPort.ReadBufferSize);
						String SerialIn = System.Text.Encoding.Default.GetString(readBuffer,0,count);
						DataReceived(SerialIn);
					}
					catch (TimeoutException) { }
				}
				else
				{
					TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
					Thread.Sleep(waitTime);
				}
			}
		}







		/// <summary> Open the serial port with current settings. </summary>
        public void Open()








        {
			Close();



            try
            {
                _serialPort.PortName = Settings.Port.PortName;
                _serialPort.BaudRate = Settings.Port.BaudRate;
                _serialPort.Parity = Settings.Port.Parity;
                _serialPort.DataBits = Settings.Port.DataBits;
                _serialPort.StopBits = Settings.Port.StopBits;
                _serialPort.Handshake = Settings.Port.Handshake;



				// Set the read/write timeouts
				_serialPort.ReadTimeout = 50;
				_serialPort.WriteTimeout = 50;




				_serialPort.Open();
				StartReading();
			}
            catch (IOException)
            {
                StatusChanged(String.Format("{0} does not exist", Settings.Port.PortName));
            }
            catch (UnauthorizedAccessException)
            {
                StatusChanged(String.Format("{0} already in use", Settings.Port.PortName));
            }
            catch (Exception ex)
            {
                StatusChanged(String.Format("{0}", ex.ToString()));
            }






            // Update the status
            if (_serialPort.IsOpen)
            {
                string p = _serialPort.Parity.ToString().Substring(0, 1);   //First char
                string h = _serialPort.Handshake.ToString();
                if (_serialPort.Handshake == Handshake.None)
                    h = "no handshake"; // more descriptive than "None"



                StatusChanged(String.Format("{0}: {1} bps, {2}{3}{4}, {5}",
                    _serialPort.PortName, _serialPort.BaudRate,
                    _serialPort.DataBits, p, (int)_serialPort.StopBits, h));
            }
            else
            {
                StatusChanged(String.Format("{0} already in use", Settings.Port.PortName));
            }



        }

        /// <summary> Close the serial port. </summary>
        public void Close()











        {
			StopReading();
			_serialPort.Close();
            StatusChanged("connection closed");

        }

        /// <summary> Get the status of the serial port. </summary>
        public bool IsOpen









        {
            get
            {
                return _serialPort.IsOpen;
            }

        }

        /// <summary> Get a list of the available ports. Already opened ports
        /// are not returend. </summary>
        public string[] GetAvailablePorts()




        {
            return SerialPort.GetPortNames();

        }

        /// <summary>Send data to the serial port after appending line ending. </summary>
        /// <param name="data">An string containing the data to send. </param>
        public void Send(string data)









        {
            if (IsOpen)
            {
                string lineEnding = "";
                switch (Settings.Option.AppendToSend)
                {
                    case Settings.Option.AppendType.AppendCR:
                        lineEnding = "\r"; break;
                    case Settings.Option.AppendType.AppendLF:
                        lineEnding = "\n"; break;
                    case Settings.Option.AppendType.AppendCRLF:
                        lineEnding = "\r\n"; break;
                }



                _serialPort.Write(data + lineEnding);
            }






        }


    }
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ocaccy

ASKER

The why of my question is as follows.
I have 6 RS485 devices connected to the computer through a converter RS485/USB.
To get the data I need to send a command to each device. id01, id02, id03, id04, id05, id06 twice.

XX and YY
Are defective, analyze and help me please.
In the twentieth sending twice the same data often return only once, but sometimes I get duplicate data and need to clean it.

The why of my question is as follows.
I have 6 RS485 devices connected to the computer through RS485/USB to convert.
To get the data I need to send a command to each device. id01, id02, id03, id04, id05, id06 twice.

The first time the sensor is ready.
The second time the device invoked responds.
Sometimes I get 2 times the same id return due to the fact that 2 times to send the same command.
But only want to get the data one time every 10 seconds. Hence my question to reset the buffer.
I have two buttons that do the work sending commands.
XX and YY
Are defective, analyze and help me please.
In the twentieth sending twice the same data often return only once, but sometimes I get duplicate data and need to clean it.

How to fix this?
XX
private void button33_Click(object sender, EventArgs e)
        {
            timer3.Enabled = true;
            inicio = DateTime.Now;
            #region TRABALHA ID01
            timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID01_c = "id01";
            CommPort com = CommPort.Instance;
            s_ID01_c = ConvertEscapeSequences(s_ID01_c); ;
            com.Send(s_ID01_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID01_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

            #region TRABALHA ID02
            //timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID02_c = "id02";
            //CommPort com = CommPort.Instance;
            s_ID02_c = ConvertEscapeSequences(s_ID02_c); ;
            com.Send(s_ID02_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID02_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

            #region TRABALHA ID03
            //timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID03_c = "id03";
            //CommPort com = CommPort.Instance;
            s_ID03_c = ConvertEscapeSequences(s_ID03_c); ;
            com.Send(s_ID03_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID03_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

            #region TRABALHA ID04
            //timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID04_c = "id04";
            //CommPort com = CommPort.Instance;
            s_ID04_c = ConvertEscapeSequences(s_ID04_c); ;
            com.Send(s_ID04_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID04_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

            #region TRABALHA ID05
            //timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID05_c = "id05";
            //CommPort com = CommPort.Instance;
            s_ID05_c = ConvertEscapeSequences(s_ID05_c); ;
            com.Send(s_ID05_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID05_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

            #region TRABALHA ID06
            //timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID06_c = "id06";
            //CommPort com = CommPort.Instance;
            s_ID06_c = ConvertEscapeSequences(s_ID06_c); ;
            com.Send(s_ID06_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID06_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

        }

Open in new window

YY

private void button10_Click(object sender, EventArgs e)
        {
            //Thread.Sleep(150); // Dorme por 150 segundos
            timr_ID06.Enabled = true;

            a++;
            lbl_count.Text = a.ToString();
            textBox2.Clear();
            CommPort com = CommPort.Instance;

            for (int i = 0; i <= 12; i++)
            {
                //string idX = "id100";
                //if (i = 1||i=2||i=3||i=4||i=5||i=6)
                //{
                string vstr = "ID0" + i.ToString();
                vstr = ConvertEscapeSequences(vstr);
                com.Send(vstr);
                com.Send(vstr);
                //}
                // idX = ConvertEscapeSequences(idX);

                //Thread.Sleep(500);
                //com.Send(idX);

            }

        }

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ocaccy

ASKER

Hi, AndyAinscow and mcs0506.

No, I don´t create another buffer.
My question is wrong!

Having the 6 devices.
ID01, ID02, ID03, ID04, ID05, ID06.
I need to send the command to access the devices at intervals of 10 seconds.
The button is up. XX or YY

I get the data in: RECEIVING DATA below.
Through the code and the problem is:

I think the logic, or event triggered by the button, to send commands and receive data, are wrong.
Sometimes I get no data.
Or because the devices did not receive the command, or collided, still do not know.
Thread.Sleep(150);
If  Thread.Sleep(20);

Receive error message .....Length....
And the pointer stop in this line.

if (InvokeRequired)
            {
               Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
                return;
            }



RECEIVING DATA

        #region Event handling - data received and status changed

        /// <summary>
        /// Prepare a string for output by converting non-printable characters.
        /// </summary>
        /// <param name="StringIn">input string to prepare.</param>
        /// <returns>output string.</returns>
        private String PrepareData(String StringIn)
        {
            // The names of the first 32 characters
            string[] charNames = {
                                 // "NUL", "SOH", "STX", "ETX", "EOT",
                //"ENQ", "ACK", "BEL", "BS", "TAB", "LF", "VT", "FF", "CR", "SO", "SI",
                //"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB",
                //"ESC", "FS", "GS", "RS", "US", "Space"
                                 };

            string StringOut = "";

            foreach (char c in StringIn)
            {
                if (Settings.Option.HexOutput)
                {
                    StringOut = StringOut + String.Format("{0:X2} ", (int)c);
                }
                else if (c < 32 && c != 9)
                {
                    StringOut = StringOut + "";// +"<"+charNames[c]+">";

                    //Uglier "Termite" style
                    //StringOut = StringOut + String.Format("[{0:X2}]", (int)c);
                }
                else
                {
                    StringOut = StringOut + c;
                }
            }
            return StringOut;
        }

        /// <summary>
        /// Partial line for AddData().
        /// </summary>
        private Line partialLine = null;

        /// <summary>
        /// Add data to the output.
        /// </summary>
        /// <param name="StringIn"></param>
        /// <returns></returns>
        private Line AddData(String StringIn)
        {
            String StringOut = PrepareData(StringIn);

            // if we have a partial line, add to it.
            if (partialLine != null)
            {
                // tack it on
                partialLine.Str = partialLine.Str + StringOut;
                outputList_Update(partialLine);
                return partialLine;
            }

            return outputList_Add(StringOut, receivedColor);
        }

        // delegate used for Invoke
        internal delegate void StringDelegate(string data);

        /// <summary>
        /// Handle data received event from serial port.
        /// </summary>
        /// <param name="data">incoming data</param>
        public void OnDataReceived(string dataIn)
        {
            //Handle multi-threading
            if (InvokeRequired)
            {
                Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
                return;
            }

            // pause scrolling to speed up output of multiple lines
            bool saveScrolling = scrolling;
            scrolling = false;

            // if we detect a line terminator, add line to output
            int index;
            while (dataIn.Length > 0 &&
                ((index = dataIn.IndexOf("\r")) != -1 ||
                (index = dataIn.IndexOf("\n")) != -1))
            {
                String StringIn = dataIn.Substring(0, index);
                dataIn = dataIn.Remove(0, index + 1);

                logFile_writeLine(AddData(StringIn).Str);
                logFile_writeLine1(AddData(StringIn).Str);
                //listBox3.Items.Add(AddData(StringIn).Str);
                partialLine = null;	// terminate partial line
            }

            // if we have data remaining, add a partial line
            if (dataIn.Length > 0)
            {
                partialLine = AddData(dataIn);
            }

            // restore scrolling
            scrolling = saveScrolling;
            outputList_Scroll();
            listBox1_Scroll();
        }

Open in new window

Avatar of ocaccy

ASKER

We had a problem of not receiving data, and receive duplicate data from the serial port with 6 devices RS485/USB, connected to the pc by a converter USB/RS485.

We solve the problem.

I used the code below.

Best Regards,
ocaccy.
// timer-10 interval= 10000ms
// timer-01 interval= 200ms
// timer-02 interval= 200ms
// timer-03 interval= 200ms
// timer-04 interval= 200ms
// timer-05 interval= 200ms
// timer-06 interval= 200ms

 private void GetData_Click(object sender, EventArgs e)
        {
            timer_10.Enabled = true;
        }

 private void timer_10_Tick(object sender, EventArgs e)
        {
            timer_01.Enabled = true;
        }


#region timer_01_Tick 
private void timer_01_Tick(object sender, EventArgs e)
        {
            #region WORKING ID01
            this.dataReceived = false;
            send_t = 0;
            free1.Enabled = true;
            #endregion
        }

private void free1_Tick(object sender, EventArgs e)
       {
            if (send_t == 3)
            {
                this.dataReceived = true;
            }
            if (this.dataReceived == false)
            {
                string s_ID01_c = "id01";
                CommPort com = CommPort.Instance;
                s_ID01_c = ConvertEscapeSequences(s_ID01_c);
                com.Send(s_ID01_c);
                send_t = send_t + 1;

            }
            else
            {
                free1.Enabled = false;
                timer_02.Enabled = true;
                timer_01.Enabled = false;
            }
        }
        #endregion

// After ends 01, chage to 02, to 03...........

Open in new window

Avatar of ocaccy

ASKER

We had a problem of not receiving data, and receive duplicate data from the serial port with 6 devices RS485/USB, connected to the pc by a converter USB/RS485.

We solve the problem.

I used the code below.

Best Regards,
ocaccy.

// timer-10 interval= 10000ms
// timer-01 interval= 200ms
// timer-02 interval= 200ms
// timer-03 interval= 200ms
// timer-04 interval= 200ms
// timer-05 interval= 200ms
// timer-06 interval= 200ms

 private void GetData_Click(object sender, EventArgs e)
        {
            timer_10.Enabled = true;
        }

 private void timer_10_Tick(object sender, EventArgs e)
        {
            timer_01.Enabled = true;
        }


#region timer_01_Tick
private void timer_01_Tick(object sender, EventArgs e)
        {
            #region WORKING ID01
            this.dataReceived = false;
            send_t = 0;
            free1.Enabled = true;
            #endregion
        }

private void free1_Tick(object sender, EventArgs e)
       {
            if (send_t == 3)
            {
                this.dataReceived = true;
            }
            if (this.dataReceived == false)
            {
                string s_ID01_c = "id01";
                CommPort com = CommPort.Instance;
                s_ID01_c = ConvertEscapeSequences(s_ID01_c);
                com.Send(s_ID01_c);
                send_t = send_t + 1;

            }
            else
            {
                free1.Enabled = false;
                timer_02.Enabled = true;
                timer_01.Enabled = false;
            }
        }
        #endregion

// After ends 01, chage to 02, to 03...........