Handle serial thread event in WPF GUI class - c#

I have a serial port class, and I would like to control send/receive via my GUI, and have the GUI update based on receipt of data from the serial port (or other events). So the two relevant classes are the serial class and the main window class.
I have the code below which compiles, but I get an exception when I try to run.
public class MySerThread
{
public SerialPort serport;
public event SerialDataReceivedEventHandler newSerData;
public MySerThread()
{
serport = new SerialPort("COM1", 115200);
serport.Open();
serport.DataReceived += DataReceivedHandler;
}
public void DataReceivedHandler(object s, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[serport.BytesToRead];
serport.Read(data, 0, data.Length);
// here's where I think I'm going wrong?
if(newSerData != null)
newSerData(s,e);
}
}
And then in my GUI class...
public partial class MainWindow : Window
{
MySerThread myPort;
public MainWindow()
{
// Exception triggers here
myPort.newSerData += DisplaySerDataHandler;
}
private void DisplaySerDataHandler(object sender, SerialDataReceivedEventArgs e)
{
this.ReceivedCallback(e);
}
private void ReceivedCallback(SerialDataReceivedEventArgs e)
{
if(this.someTextBlock.Dispatcher.CheckAccess())
{
this.UpdateTextBlock(e);
}
else
{
this.someTextBlock.Dispatcher.BeginInvoke(new Action<SerialDataReceivedEventArgs>(this.UpdateTextBlock), e);
}
}
private void UpdateTextBlock(SerialDataReceivedEventArgs e)
{
someTextBlock.Text = "got new data";
}
}
So, what am I doing wrong here? What is the best way to do this?

You can't access myPort without creating an instance.
MySerThread myPort = new MySerThread();

Related

Receiving data from serial port in C#, while updating ui

My question is how do you update your ui, with data from serialport, while still updating other ui components? I have tried using a background worker, but it seems to block the ui, while the data is streaming in.
Image of form:
My code is:
public partial class Form1 : Form
{
static bool _continue;
static SerialPort _serialPort;
BackgroundWorker dataWorker;
string message;
public delegate void UpdateListboxData();
private void buttonPortConnect_Click(object sender, EventArgs e)
{
// Set the read/write timeouts
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.Open();
_continue = true;
dataWorker = new BackgroundWorker();
dataWorker.RunWorkerAsync();
dataWorker.DoWork += StartDataWork;
}
private void StartDataWork(object sender, DoWorkEventArgs e)
{
Delegate del = new UpdateListboxData(DataRead);
this.Invoke(del);
}
private void DataRead()
{
while (_continue)
{
try
{
message = _serialPort.ReadLine();
}
catch (TimeoutException) { }
}
}
}
you have to use Serial Port DataReceived Event and Delegate
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (TextBox.InvokeRequired)
TextBox.Invoke(new myDelegate(updateTextBox));
}
public delegate void myDelegate();
public void updateTextBox()
{
int iBytesToRead = serialPort1.BytesToRead;
//Your Codes For reding From Serial Port Such as this:
char[] ch = new char[?];
serialPort1.Read(ch, 0, ?? ).ToString();
//........
}
The way to update a winforms UI is to use if (control.InvokeRequired) {...} and Invoke as shown in the example here How do I update the GUI from another thread?
You should not read data inside the invoke'd function. This is blocking your UI.
Either read data directly in "DoWork" and invoke the delegate only with data.
Or you might use the DataReceived event of SerialPort.

C# serial events when the serial is not in design

I added this in my code:
namespace uartToCs_version_2._0
{
public partial class formMain : Form
{
==> public static SerialPort serial = new SerialPort();
But I didn't use the design tab, so how should I go about event handling (with the current setup I can use it in other forms too, will that still be possible)?
My design file
public Form1()
{
InitializeComponent();
//add DataReceived event of serial
Form1.serial.DataReceived += serial_DataReceived;
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
//remove DataReceived event of serial
Form1.serial.DataReceived -= serial_DataReceived;
}
void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//process data here
}
You can register the events either in any method like Load() or in the constructor. I used the constructor below. You can't register event until all the needed properties are setup. I did not show the setup code.
public partial class Form1 : Form
{
public static SerialPort serial = new SerialPort();
public Form1()
{
InitializeComponent();
serial.DataReceived += new SerialDataReceivedEventHandler(serial_DataReceived);
}
private void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
}
}

C#: DataReceived Event handler for serialPort not firing

I'm writing a fairly basic application, where one of the tasks is communicating with an Arduino Uno card.
I would like to write the serial communication as a separate module, so the forms only calls for the input from Arduino, and the module will handle the creating and opening of the serialPort and reading data from it.
For testing purposes I wrote a program for the Arduino which prints the elapsed milliseconds every half second to the serialPort.
I would like to populate the textBox of my Form with the output from Arduino after I press a button.
I create the serialPort in the SerialComm class, and although I attach a DataReceived event handler to it, it never seems to fire.
Here is the code for the SerialComm class:
class SerialComm
{
private List<String> availablePorts;
private SerialPort arduino;
private string receivedText;
public String[] portList
{ get
{
EnumPorts();
return availablePorts.ToArray();
}
}
public string receivedData
{
get
{
return receivedText;
}
}
public void InitialiseSerial()
{
arduino = new SerialPort();
arduino.BaudRate = 9600;
arduino.DtrEnable = true;
// Add event handler
arduino.DataReceived += new SerialDataReceivedEventHandler(arduino_DataReceived);
}
public void EnumPorts()
{
availablePorts = new List<string>();
foreach (string s in SerialPort.GetPortNames())
{
availablePorts.Add(s);
}
}
public void StartMC(SerialPort serialPort, String portName)
{
arduino = serialPort;
if (arduino.IsOpen)
{
arduino.Close();
}
else
{
//Initialise Serial Port
arduino.PortName = portName;
arduino.Open();
}
}
//This never fires==================
private void arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
receivedText = arduino.ReadExisting();
}
public void CloseMC()
{
if (arduino.IsOpen)
{
arduino.Close();
arduino.Dispose();
}
}
}
In the Form I call the text from Arduino like this: (I have a button (Button1), a combobox for selecting the COM port (comboBox1) and a textBox on the Form)
public partial class Form1 : Form
{
SerialComm arduino = new SerialComm();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Arduino
arduino.InitialiseSerial();
String[] portList = arduino.portList;
foreach (String COM in portList)
{
comboBox1.Items.Add(COM);
}
if (portList.Length > 0)
{
comboBox1.SelectedItem = comboBox1.Items[0];
}
else
{
comboBox1.Text = "No microcontroller found!";
}
}
private void button1_Click(object sender, EventArgs e)
{
arduino.StartMC(serialPort1, comboBox1.SelectedItem.ToString());
//as the DataReceived never fires arduino.receivedData stays null
if (arduino.receivedData != null)
{
for (int i = 0; i < 101; i++)
{
textBox1.AppendText(arduino.receivedData);
}
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
arduino.CloseMC();
}
}
Do you see any reason why the event handler doesn't trigger?
Thank you very much for your help in advance.
Best Regards,
Peter

Using same serial port data received event on two different forms

I have a problem with my SerialDataReceivedEventHandler whitch fails to respond to data in serail port.
I have one main form in whitch i open port and do other stuf whitch need to be done for proper serial port communication (sending and receiving work)!
Then i open another form in same project whitch need same serial port for reading and writing!
Problem is that my SerialDataReceivedEventHandler in form2 not working jet it is completely identical to the first in mainform. (if i call serial.close() in main form app freezes or cause huge delay)
probably i have to make in my main from this event public, but i still don't konow how to make my custom event or something else that will trigger the event in form 2 that data is arrived on port
I found this link for help but does not work with my app.
http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/7efccf0e-b412-4869-b942-a006773a833f
i'm using VS2008,framework3.5 (smart device project)
can somebody help me with that? , Please!
Move your SerialPort consumption into a separate static (or a singleton) class. Create a DataReceived event in that class and fire it every time data is received. Have both forms subscribe to the DataReceived event - this way both forms will receive the data.
Edit 1: Sample in pseudo code
public static class Serial {
public static delegate void DataReceivedEventHandler(object sender, ReceivedEventArgs e);
public static event DataReceivedEventHandler DataReceived;
static SerialPort serialPort = new SerialPort();
static Serial() {
serialPort = new SerialPort();
serialPort.DataReceived += Incoming;
serialPort.Open();
}
private static void Incoming(object sender, SerialDataReceivedEventHandler args) {
if (DataReceived != null) {
ReceivedEventArgs rea = new ReceivedEventArgs {Data = args.Data};
DataReceived(this, rea);
}
}
}
public class ReceivedEventArgs : EventArgs {
public string Data { get; set;}
}
public class Form1: Form {
public Form1() {
Serial.DataReceived += Incoming;
}
private void Incoming(object sender, ReceivedEventArgs e) {
// you receive the data here
Debug.WriteLine(e.Data);
}
}
public class Form2: Form {
public Form2() {
Serial.DataReceived += Incoming;
}
private void Incoming(object sender, ReceivedEventArgs e) {
// you receive the data here
Debug.WriteLine(e.Data);
}
}
Again, this is pseudo code, without compiler nearby. Hope this helps.

SerialPort Buffer on New Thread

I have a MySerialPort class/object accessed from FormGUI. After creating a MySerialPort object, I want to open it, and keep receiving data continuously. The data will be stored and managed in the object's data buffer. FormGUI's memoEdit will show the received codes from the MySerialPort object's buffer.
How can I use "new Thread()" with the [port].ReadExisting method?
using System;
using System.IO.Ports;
using System.Threading;
class MySerialPort
{
public SerialPort CreatePort(string portName, int portSpeed, int portParity, int portDataSize, int portStopBits)
{
// fixed values while testing
var port = new SerialPort("COM6", 9600, Parity.None, 8, StopBits.One);
return port;
}
public void OpenPort(SerialPort port)
{
port.Open();
new Thread(() => port.ReadExisting).Start();
while (true)
{
// Send to buffer
// Maybe some break condition
}
}
The Observer pattern is working now, I got the data I was expecting from the serial port, thanks Henk.
public partial class MyGUI : Form
{
private MySerialPort MyPort = new MySerialPort();
public MyGUI()
{
InitializeComponent();
MyPort.OnDataBufferUpdate += DisplayNewData;
}
public void DisplayNewData(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate() { DisplayNewData(sender, e); }));
}
else
{
memoEdit.Text = MyPort.DataBuffer;
}
}
}
public class MySerialPort
{
public MySerialPort()
{
// Initialize serial port
_Port.DataReceived += _Port_DataReceived;
}
public delegate void HandleDataBufferUpdate(object sender, EventArgs e);
public event HandleDataBufferUpdate OnDataBufferUpdate = delegate {};
private void _Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Set _Port.DataBuffer from serial port buffer, then activate event below to signal form
OnDataBufferUpdate(this, EventArgs.Empty);
}
}

Categories

Resources