13 Replies - 4128 Views - Last Post: 12 December 2010 - 07:11 PM Rate Topic: -----

#1 questuk  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 30-November 10

Background worker & RS232 how?

Posted 09 December 2010 - 05:57 AM

Hi,

New to C#

I want to use the backgroundworker to start communicating via RS232 port.

I have set up the RS232 and this is working, but I am having trouble getting text into the textbox. I have used the invoke method and this worked but then i added another textbox and got a cross thread exception.

Having read about the backgroundworker it seems easier for a beginner to start with.

But i know a serialport event will be raised when data arrives, but can i put the data string into a textbox on the UI thread or is it still on the worker thread?

Any help appreciated as I have read many articles but still not found a soultion.

And a few lines of code would help.

Thanks

Regards


Gary

This post has been edited by questuk: 09 December 2010 - 05:59 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Background worker & RS232 how?

#2 mavarazo  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 36
  • View blog
  • Posts: 181
  • Joined: 25-October 10

Re: Background worker & RS232 how?

Posted 09 December 2010 - 06:02 AM

Any few code lines would be helpful :)
Was This Post Helpful? 0
  • +
  • -

#3 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,957
  • Joined: 21-March 08

Re: Background worker & RS232 how?

Posted 09 December 2010 - 06:39 AM

we definitely need to see your code.
Was This Post Helpful? 0
  • +
  • -

#4 questuk  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 30-November 10

Re: Background worker & RS232 how?

Posted 09 December 2010 - 07:16 AM

View Posteclipsed4utoo, on 09 December 2010 - 05:39 AM, said:

we definitely need to see your code.


Hi,

Please find below my code NOT using backgroundworker.

It gets text from RS232 then checks for a Match = gas1
If this is received then updates a counter.


This works until the counter textbox is increased then i get a thread exception crossed etc.

Apologise for the rought state of my code but its work in progress.

#region Notes

/* 		http://www.codeproject.com/KB/system/rs232ThreadSafe.aspx


      	To make a thread-safe call a Windows Forms control:

        1.  Query the control's InvokeRequired property.
        2.  If InvokeRequired returns true,  call Invoke with a delegate that
 			makes the actual call to the control.
        3.  If InvokeRequired returns false, call the control directly.

        In the following code example, this logic is implemented in a utility
 		method called SetText.
        A delegate type named SetTextDelegate encapsulates the SetText method.
        When the TextBox control's InvokeRequired returns true, the SetText 
		method creates an instance
        of SetTextDelegate and calls the form's Invoke method.
        This causes the SetText method to be called on the thread that created 
		the TextBox control,
        and in this thread context the Text property is set directly

        also see: http://msdn2.microsoft.com/en-us/library/ms171728(VS.80).aspx
        This method demonstrates a pattern for making thread-safe
      	calls on a Windows Forms control.
        
       	If the calling thread is different from the thread that
       	created the TextBox control, this method creates a
      	SetTextCallback and calls itself asynchronously using the
       	Invoke method.
        
         If the calling thread is the same as the thread that created
         the TextBox control, the Text property is set directly.
*/


#endregion

#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
#endregion

#region namespace
namespace RS232
    {
#endregion

#region class RS232Test
    public partial class RS232Test : Form
        {
#endregion

#region Declarations
        public string GB_temp;
        string InputData = ""; 					        // Was String.Empty;
 		bool have_data_flag = false;
 		int count = 0;
 		int number = 1000; 		
 		
        delegate void SetTextCallback(string text);		
        // This delegate enables asynchronous calls for setting
		// the text property on a TextBox control:
#endregion

#region 	RS232Test Constructor?
        public RS232Test()
        {
            {
            InitializeComponent();
            Counter();
          
              	string[] ports = SerialPort.GetPortNames();	// Nice methods to browse all available ports:            
           	 	foreach (string port in ports)				// Add all port names to the combo box:
                {
                cmbComSelect.Items.Add(port);               
                }
        	}
        }
#endregion

#region GB_Main
        public void GB_Main() // Looks for gas1 to be sent in via RS232 serial
           {         		  // If correct updated CounterTextBox.
            if (GB_temp == "gas1")
            {
            InputData = "*** Got correct Data ***"; 
            SetText(InputData);
            count ++;
            Counter();
            }     
           }
        
#endregion
           
#region check_flags
        public void check_flags()
            {
            if (GB_temp == "gb")
                {
                SetText(" MATCH ");
                }
            }
#endregion

#region SetUp Ports
        private void cmbComSelect_SelectionchangeCommitted(object sender, EventArgs e)
            {
            if (port.IsOpen)
                port.Close();
            port.PortName = cmbComSelect.SelectedItem.ToString();
            stsStatus.Text = port.PortName + ": 9600,8N1";

            try 				// try to open the selected port:
                {
                port.Open();
                }            
            catch				// give a message, if the port is not available:
            	
                {
                MessageBox.Show("Serial port " + port.PortName + " cannot be opened!", "RS232 tester",
            	                MessageBoxButtons.OK, MessageBoxIcon.Warning);
            	
                cmbComSelect.SelectedText = "";
                stsStatus.Text = "Select serial port!";
                }
            }
        
#endregion

#region btnSend_Click Event
        private void btnSend_Click(object sender, EventArgs e)
            {
            if (port.IsOpen)
                port.WriteLine(GUI_TextBox_OUT.Text);
            else
                MessageBox.Show("Serial port is closed!", "RS232 tester", MessageBoxButtons.OK,
            	                MessageBoxIcon.Error);
            
            GUI_TextBox_OUT.Clear();
            
            SetText(" GBTemp is = ");// Is this set from GUI Thread ?
			SetText(GB_temp);// Is this set from GUI Thread ?
			
            }
#endregion Event

#region btnClear_Click Event
        private void btnClear_Click(object sender, EventArgs e)
            {
            GUI_TextBox_IN.Clear();
            }
#endregion 

#region port_DataReceived_1 Event
        private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
            {
            InputData = port.ReadExisting();
            if (InputData != String.Empty)
                
            	{
                SetText(InputData);
				GB_temp = InputData;
                have_data_flag = true;
                 GB_Main();
                }
            }  
#endregion        

#region SetText
        private void SetText(string text)
            {
            if (this.GUI_TextBox_IN.InvokeRequired) // Note A            
                
            	{
                SetTextCallback GB_SetTextCallback = new SetTextCallback(SetText); // Note B               
                this.Invoke(GB_SetTextCallback, new object[] {"\r\n" + text });
                
               
                }
            
            else
                this.GUI_TextBox_IN.Text += text;
            
            /* Note A
            	InvokeRequired required compares the thread ID of the
             	calling thread to the thread ID of the creating thread.
           		If these threads are different, it returns true.
           		
           		Note B
           		SetTextCallback was set at start as Delegate in 'public partial class RS232Tester : Form'
                GB_SetTextCallback was 'd'

            */
            }
#endregion

#region Counter
public void Counter()
{
            CounterTextBox.Text = Convert.ToString (count);	
}
#endregion


#region semi-colons hidden here
        }   
    }   
#endregion
     
     
     
     



Was This Post Helpful? 0
  • +
  • -

#5 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,957
  • Joined: 21-March 08

Re: Background worker & RS232 how?

Posted 09 December 2010 - 07:51 AM

You should be invoking the delegate in the DataReceived event. That event is run on a background thread by the framework.

Take a look at this snippet that I did on sending data to a serial port and then writing the returned data back to a Textbox on the form.
Was This Post Helpful? 0
  • +
  • -

#6 questuk  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 30-November 10

Re: Background worker & RS232 how?

Posted 09 December 2010 - 08:08 AM

View Posteclipsed4utoo, on 09 December 2010 - 06:51 AM, said:

You should be invoking the delegate in the DataReceived event. That event is run on a background thread by the framework.

Take a look at this snippet that I did on sending data to a serial port and then writing the returned data back to a Textbox on the form.



Hi,

I cannot try this the moment as I am at work. (and its hard too understand at the moment).

I have moved the Invoke etc to the data received event, would you be kind enought to put the lines in there correct order if they are wrong?


 private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
            {
if (this.GUI_TextBox_IN.InvokeRequired) // Note A            
                
            	{
                SetTextCallback GB_SetTextCallback = new SetTextCallback(SetText); // Note B               
                this.Invoke(GB_SetTextCallback, new object[] {"\r\n" + text });
                
               
                }
            
            else
                this.GUI_TextBox_IN.Text += text;



            InputData = port.ReadExisting();
            if (InputData != String.Empty)
                
            	{
                SetText(InputData);
				GB_temp = InputData;
                have_data_flag = true;
                 GB_Main();
                }
            } 



Thanks

Gary

This post has been edited by questuk: 09 December 2010 - 08:09 AM

Was This Post Helpful? 0
  • +
  • -

#7 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5439
  • View blog
  • Posts: 11,669
  • Joined: 02-June 10

Re: Background worker & RS232 how?

Posted 09 December 2010 - 12:05 PM

The long and the short of it is this:
Do not try to change the contents of a GUI object like a textbox from another thread. Period.
Your backgroundworker should raise an event that your GUI thread is subscribed to.
When your backgroundworkerthread yells out the event "I have a message and here it is: xxxxxx", your GUI thread hears that event and reacts appropriately.


Your RS-232 thread should NOT understand a single thing about the GUI. It is not the job of the RS-232 thread to understand the GUI. Keep your RS-232 thread clean and just doing COM port stuff. Keep your GUI thread clean and just doing GUI stuff.


Quick and easy custom events
Bulding an application - Part 1
Was This Post Helpful? 1
  • +
  • -

#8 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,957
  • Joined: 21-March 08

Re: Background worker & RS232 how?

Posted 09 December 2010 - 12:44 PM

this should work....

private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
     string text = port.ReadExisting();
     if (this.GUI_TextBox_IN.InvokeRequired)         
     {
         SetTextCallback GB_SetTextCallback = new SetTextCallback(SetText); // Note B               
         this.BeginInvoke(GB_SetTextCallback, new object[] {"\r\n" + text });
     }
     else
         this.GUI_TextBox_IN.Text += text;

     GB_temp = text;
     have_data_flag = true;
 
     // not sure what this method does, but if it tries to set 
     //   UI control values, then it's going to fail also    
     GB_Main();
}


Was This Post Helpful? 1
  • +
  • -

#9 questuk  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 30-November 10

Re: Background worker & RS232 how?

Posted 09 December 2010 - 01:12 PM

Quote

Your RS-232 thread should NOT understand a single thing about the GUI. It is not the job of the RS-232 thread to understand the GUI. Keep your RS-232 thread clean and just doing COM port stuff. Keep your GUI thread clean and just doing GUI stuff.


Hi tlhIn'toq,

Yes that is how I want it to be.

I haven't tried the Backgroundworked method yet as perhaps my code is near being correct?

I have spent 30 hours on this over the last week trying to understand what I am doing wrong, and am prepared to put lots more effort into this if required.

Thanks for your help.

Quote

// not sure what this method does, but if it tries to set
// UI control values, then it's going to fail also
GB_Main();


HI eclipsed4utoo,

Thanks for the updated code, but as you suggested it gives cross thread excepetion on a match of = gas1 in my GB_Main.



It may be best if i give everyone an outline of what I am trying to do:

A sensor sends messages to the RS232 port, amongst these messages will be "gas1"
When there is a match i need to update the Count by 1 and display the count in a TextBox_count window, and also Display Gas1 in the TextboxIN window.

I want to keep the RS232 method just for that nothing else.
GB_Main is where i tell the program what to do when it receives a string of data from the dataReceivedEvent. It also tells the Count window to increment. It will also take any other actions required in GB_Main.

I hope i have given a clearer idea of what i want to do, and I know i need help and I know I need to learn alot more.
If I can just get past this stumbling block of how to update textboxs only from the UI thread. I will then put in the effort to understand how this is achieved?

Thanks to both of you for your help

If my work so far isn't correct and I need to start again thats fine.

Thanks


Gary
Was This Post Helpful? 0
  • +
  • -

#10 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5439
  • View blog
  • Posts: 11,669
  • Joined: 02-June 10

Re: Background worker & RS232 how?

Posted 09 December 2010 - 06:21 PM

Personally I would make an RS232GasControl component. A stand alone control just like a button, or DateTimePicker.
It would have properties for COMport, BaudRate etc.
It would have methods like "StartWatching", "StopWatching" etc.
It should raise events like "NewReading" with an event argument of the new reading value.

Now you just drag and drop the you new cool RS232GasControl from the ToolBox to your form... assign the properties... and subscribe to the events. Again, just like a button where you assign the background color and subscribe to the .Click event.

This will isolate your gas meter and allow your form to react however it should when a new reading comes in. The gas meter control will have one job only: To deal with the RS232 port and translate the messages into the proper events.

The tutorial links I provided earlier would show you how to make it.
Was This Post Helpful? 0
  • +
  • -

#11 questuk  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 30-November 10

Re: Background worker & RS232 how?

Posted 10 December 2010 - 07:32 AM

Hi,

Thanks for that info, that will be my end target on how i want this to work.

At the moment have a few questions to try and get some of my original code working.

Do I have to do something like the following for all TextBoxs that i may creat in the future? (Obviously i will change the names etc)


 if (this.GUI_TextBox_IN.InvokeRequired)          
180	                 
181	                {
182	                SetTextCallback GB_SetTextCallback = new SetTextCallback(SetText); // Note B              
183	                this.Invoke(GB_SetTextCallback, new object[] {"\r\n" + text });
184	                 
185	                
186	                }
187	             
188	            else
189	                this.GUI_TextBox_IN.Text += text;




Also I do need to make a Delegate for each thread i create?

Regards


Gary
Was This Post Helpful? 0
  • +
  • -

#12 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,957
  • Joined: 21-March 08

Re: Background worker & RS232 how?

Posted 10 December 2010 - 09:11 AM

1. If you want the textbox to be changed from another thread, then yes, you will need to invoke the method using a delegate.

2. No, you don't need a delegate for every thread. What the delegate does is it will process the method(SetText) on the thread of the invoking control(this == the form(i normally use the textbox instead of the form)). Therefore, the method is being executed on the UI thread. You can use this same delegate for any/all threads.
Was This Post Helpful? 1
  • +
  • -

#13 questuk  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 30-November 10

Re: Background worker & RS232 how?

Posted 11 December 2010 - 10:54 AM

Hi,

Is there a way of knowing which thread your in ?

Either using some part of the IDE or some code that I add to my code?

Or is it obvious when experienced at C#, just looking at the code?

Any tips!

Thanks

Regards


Gary
Was This Post Helpful? 0
  • +
  • -

#14 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,957
  • Joined: 21-March 08

Re: Background worker & RS232 how?

Posted 12 December 2010 - 07:11 PM

Do you need to know which thread you are in?
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1