PDA

View Full Version : C# Multithreading... Ugh I'm lost here



nagmier
08-13-2009, 02:46 PM
Here is what I have so far, I have my arduino spitting out the following via serial @ 19200 (thinking I'll need to up this to 115200 soon):
c_us1:xxx
c_ir1:xxx
c_sp1:xxx

over and over the x's being sonar and ir reading and servo position
this being for a single "sensor array" eventually I plan on adding a
Left and right for more data but thats down the road at best.

Given that data I am trying to write C# App in VS 2008 Express that will read from the serial port and print the data to a text box. As of right now I can get that to happen.... wait for it.... Only when I press a button (or generate an event). I would like to be able to click the start button and have it do this continuously in the background. Now from what I gathered in my googling over the last 2-3 days is that I must learn this mystic art of "Threading"?

Number one is that the case? Number 2 if so I have looked at a few tutorials and don't think I grasp it enough could you point me in the direction of a tutorial with code and explanation? Also I can post my current code (no threading) if needed.

MikeG
08-13-2009, 07:59 PM
Subscribe to the DataReceived event of the serial port class?

Don't know what you're doing though... post your code.

nagmier
08-14-2009, 01:49 AM
I FINALLY Got it figured out... and for those in the future...


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Timers;

namespace Form
{
public partial class Form1 : Form
{
// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void SetTextCallback(string text);

// This BackgroundWorker is used to demonstrate the
// preferred way of performing asynchronous operations.
private BackgroundWorker backgroundWorker1 = new BackgroundWorker();

//private System.ComponentModel.IContainer components = null;

public Boolean isReading = false;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
arduinoPort.BaudRate = 19200;
arduinoPort.PortName = "COM4";
}

private void btnStart_Click(object sender, EventArgs e)
{
isReading = true;
//Lets make sure the port is open before we begin
if (arduinoPort.IsOpen == false) arduinoPort.Open();
//I should probably throw an error handler in here for the com port *shrug
setTextBackgroundWorker(this);
}

// This method is passed in to the SetTextCallBack delegate
// to set the Text property of textBox1.
private void SetText(string var)
{
string readIt = arduinoPort.ReadLine();
this.textBox1.AppendText(readIt);
}

// This method starts BackgroundWorker by calling
// RunWorkerAsync. The Text property of the TextBox control
// is set by a method running in the main thread
// when BackgroundWorker raises the RunWorkerCompleted event.
private void setTextBackgroundWorker(object sender)
{
this.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandl er(this.backgroundWorker1_RunWorkerCompleted);
this.backgroundWorker1.RunWorkerAsync();
// Continue in the main thread.
textBox1.AppendText("Written by the main thread.");
}

// This method does the work you want done in the background.
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (isReading)
{
if (this.textBox1.InvokeRequired)
{
String var = "";
// It's on a different thread, so use Invoke.
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] {var});
// See Below if passing a variable is needed
//(d, new object[] {var});
}
}
}

// This method is called by BackgroundWorker's
// RunWorkerCompleted event. Because it runs in the
// main thread, it can safely set textBox1.Text.
private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
textBox1.AppendText("Main After BG Complete");
}

private void btnStop_Click(object sender, EventArgs e)
{
isReading = false;
}

private void buttonPortClose_Click(object sender, EventArgs e)
{
if (arduinoPort.IsOpen) arduinoPort.Close();
}







}
}

Oh and btw Thanks for the attempt to help out Mike I was about ready to give up! Thanks again tho!

darkback2
08-14-2009, 07:25 AM
Thanks for posting the solution once you found it! I sometimes forget to do that.

DB

MikeG
08-14-2009, 08:53 AM
Here's another way of doing the same thing.

Form control names
btnStart
btnStop
btnClear
txtTerminal
cboPorts
cboBaud

txtTerminal = multiline.


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;


namespace SerialPortListener
{
public partial class Form1 : Form
{
public SerialPort sPort;

public delegate void SetTextCallback(String message);

public Form1()
{
InitializeComponent();
BindSerialPorts();
BindBaudRates();
}


// Bind serial port names
protected void BindSerialPorts()
{
//Bind combobox to serial port names
foreach (string port in SerialPort.GetPortNames())
{
cboPorts.Items.Add(port);
}
}

// Bind baud rates
protected void BindBaudRates()
{
cboBaud.Items.Add(2400);
cboBaud.Items.Add(4800);
cboBaud.Items.Add(9600);
cboBaud.Items.Add(14400);
cboBaud.Items.Add(19200);
cboBaud.Items.Add(28800);
cboBaud.Items.Add(38400);
cboBaud.Items.Add(57600);
cboBaud.Items.Add(115200);
}




// Start button click
private void btnStart_Click(object sender, EventArgs e)
{
OpenPort();
}

// Stop button click
private void btnStop_Click(object sender, EventArgs e)
{
ClosePort();
}

//Clear button click
private void btnClear_Click(object sender, EventArgs e)
{
txtTerminal.Text = String.Empty;
}




// Open Port
protected void OpenPort()
{
// Create a new serial port
sPort = new SerialPort((String)cboPorts.SelectedItem, (int)cboBaud.SelectedItem);
sPort.Open();

// wire up the event handler
sPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataRece ived);

// Disable the start button
btnStart.Enabled = false;
}


// Close Port
protected void ClosePort()
{
sPort.Close();
btnStart.Enabled = true;
}

// Data Recieved handler
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
SetText(sPort.ReadExisting());
}
catch (Exception ex)
{
SetText(ex.ToString());
}
}


// Align the caller and control thread
private void SetText(String message)
{
if (txtTerminal.InvokeRequired)
{
SetTextCallback del = new SetTextCallback(SetText);
this.Invoke(del, message);
}
else
{
txtTerminal.Text += message;
}
}

}
}

Alex
08-14-2009, 08:53 AM
slick work! Isn't threading in C# fun:D

nagmier
08-14-2009, 09:25 AM
Nice Mike, much cleaner! I'm not a very clean coder and it was getting late but no way I was letting that get me before sleep last night.

Alex, threading is like going to the dentist, painful but necessary!

DB, I plan on posting source for the entire project when its complete. This is just the start of a really long project though, I doubt it will be ready for general consumption for at least 6 months or longer, I'm sure you will see snippets here and there requesting help with several more problems down the road though :D