[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 5775
  • Last Modified:

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

0
ocaccy
Asked:
ocaccy
  • 4
  • 3
4 Solutions
 
AndyAinscowCommented:
At which line is the buffer you refer to ?
0
 
mcs0506Commented:
Hi,
You have already create new buffer against read so there is no need of clearing it.

regards,

Dani
0
 
AndyAinscowCommented:
@ocaccy
I don't see any buffer that is reused and so does mcs0506 - at what line is this buffer you want to be cleared?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
ocaccyAuthor Commented:
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

0
 
AndyAinscowCommented:
At which line is the buffer you refer to ?
0
 
ocaccyAuthor Commented:
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

0
 
ocaccyAuthor Commented:
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

0
 
ocaccyAuthor Commented:
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...........
0

Featured Post

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now