Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
when a click button open port this button set the baud settings, set port name to connect with device, and create evendhandler to send command and receive data responds from port as follow

serialPortForApp.DataReceived += new SerialDataReceivedEventHandler(SerialPortInApp_DataReceived);

with these settings button LoggedDataBtn_Click works perfect with the open port button settings and with datarecieved eventhandler. but GLPBtn_Click doesnt wotk at all and application crashes.


But button GLPBtn_Click if a delete event datarecieved handle in the OpenPortBtn_Click and I delete complete the SerialPortInApp_DataReceived works perfect but my LoggedDataBtn_Click stop working

My Question is:
how to manage the datarecieved handler for any command that goes to the serial port and get responds properly.

Thank you for any suggestions and answers

What I have tried:

C#
private void LoggedDataBtn_Click(object sender, EventArgs e)
{
//Display request command sent to device in the ShowDataInScreenTxtb

ShowDataInScreenTxtb.Clear();
ShowDataInScreenTxtb.Enabled = true;

//When LoggDataBtn is pressed it Send the command LogToShow to the instrument
string LoggedDataTOshow = "?R\r\n";
string commForMeter = string.Format(LoggedDataTOshow);

try
  {
    if (serialPortForApp.IsOpen)
    {
       Thread.Sleep(2000);
       loggedData.serialPortForApp.Write(LoggedDataTOshow);
     }
   }
   catch (Exception)
   {
     ShowDataInScreenTxtb.Text = "TimeOUT Exception: Error for requested command";
   }
 }

 private void GLPBtn_Click(object sender, EventArgs e)
{
//send command to instrument

 string GLPCommand = "?G\r\n";
string GLPToShow = String.Format(GLPCommand);

 try
 {
   if (serialPortForApp.IsOpen)
   {             
    Thread.Sleep(2000);
    //write command to port
    serialPortForApp.Write(GLPToShow);
     }
 catch
     {
    //MessageBox error if data reading is not posible
    ShowDataInScreenTxtb.Text = "TimeOUT Exception";
   }


            while (DataToSetandGet != "ENDS\r")
            {

                serialPortForApp.Write("\r");
                DataToSetandGet = serialPortForApp.ReadExisting();
 ShowDataInScreenTxtb.AppendText(glpShowInMainForm.DataToSetandGet.Replace("\r", "\r\n"));
}
}


 private void OpenPortBtn_Click(object sender, EventArgs e)
        {
            //Connect Port Button allows to connect the current device base on Port and Raud settings
            try
            {
                if (PortIndexCbx.Text == "" || BaudRateIndexCbx.Text == "")
                {
                    ShowDataInScreenTxtb.Text = "Set Up your Port Settings";                    //Error message to user to set up port connection if empty selection
                }
                else
                {
                    //Get Serial Port index settings to display for users 
                    serialPortForApp.PortName = PortIndexCbx.Text;                       //ComboBox1.Text set to PortName

                    //Display to users the settings for the Baud Rate that will be listened by the Port

                    serialPortForApp.BaudRate = Convert.ToInt32(BaudRateIndexCbx.Text);      //Baudrate is set (fix.) in ComboBox2.Text

                    // Meter default setting listened through the port DataBits, Parity, StopBits,Handshake
                    serialPortForApp.DataBits = 8;                                    
                    serialPortForApp.Parity = Parity.None;                            
                    serialPortForApp.StopBits = StopBits.One;                         
                    serialPortForApp.Handshake = Handshake.XOnXOff;                   

                    //Open serial Port to allow communication between PC and device 
                    //DataReceived Implemented to read from Port sending and recieving the buttons command requested
//To receive data, we will need to create an EventHandler for the "SerialDataReceivedEventHandler"
  serialPortForApp.DataReceived += new SerialDataReceivedEventHandler(SerialPortInApp_DataReceived);

                    
                    serialPortForApp.ReadTimeout = 500;
                    serialPortForApp.WriteTimeout = 500;


                    //Once Serial port and baud rate setting are set, connection is ready to use 
                    //Open serial port for communication between device and PC
                    serialPortForApp.Open();

                    //Connect and close connection buttons Behaviour
                    progressBarPortAccess.Value = 100; 
                    OpenPortBtn.Enabled = false;                    
                    ClosePortBtn.Enabled = true;                     
                    ShowDataInScreenTxtb.Enabled = true;
                    ShowDataInScreenTxtb.Text = "";

                    
                    LoggedDataBtn.Enabled = true;                  
                    DataReadingStatusLbl.Text = "Port is Connected";
                }
            }
            catch (UnauthorizedAccessException)
            {
                ShowDataInScreenTxtb.Text = "Unauthorized Port Access";
            }

        }


 private void SerialPortInApp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
 try
 {

 // SerialPort1_DataReceived handles to recieve data from device connected to Port
Thread.Sleep(500);
 DataToSetandGet = serialPortForApp.ReadExisting();
  if (this.InvokeRequired)
   {
Invoke(new MethodInvoker(delegate { ShowDataInScreenTxtb.AppendText(DataToSetandGet.Replace("\r", "\r\n")); }));
}
 }
  catch (Exception)
{
ShowDataInScreenTxtb.Text = "TimeOUT Exception: Error Port communincation";
}
 }
Posted
Updated 19-Aug-18 18:54pm
v3
Comments
[no name] 23-Jul-18 2:57am    
Reformat your code if you want people to look at it; too much work otherwise.

The data received handler is executed in another thread. That is why you have to use Invoke to update the content of your text box from.

Similar applies to the DataToSetandGet variable used there to store the received string. You can't use it from other threads (like the GUI / main thread as in your GLPBtn_Click() function) without ensuring that only one thread accesses it at the same time.

You are also calling serialPortForApp.ReadExisting() in the above function and the received handler. That won't work too. Ask yourself: Which of the two read calls is executed?

The solution is to have only one function reading from the serial port. That is usually the received handler. If you have to access the received string from another thread, you have to use a shared variable and access it with appropriate locking mechanisms. The simplest solution would be writing a function that gets the received string as parameter and is called using Invoke() from the received handler. From within that function you can then update your text box and use the data for other purposes as well.

One technique to handle requests specific to a before send command is implementing a Finite-state machine - Wikipedia[^]. A simple example:
  • State is idle (can send command)
  • Sending a command: State is waiting for response (optionally a specific response)
  • Answer received: State is has answer
  • Answer processed: State is idle (can send next command)

Finally, there is no need to call Sleep() in a properly written multi threaded application. It should be avoided at all.
 
Share this answer
 
Comments
CPallini 23-Jul-18 3:55am    
5.
hi every one

I solve this by using Enums

I create a (public enum AppButtonState : byte) and I declared that call in my SerialPortInApp_DataReceived event. So every time a button send a command this is first assessed by the enum. It creates an independent call for each command that I want SerialPortInApp_DataReceived event to read and respond.

thank you
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900