Using same serial port instances on multiple forms - c#

I am quite new to C# and I am trying to use one common serial port for 3 different forms: Form2, Form3, Form4
Form1.cs isn't needed for this because it's just needed to launch the programs of the other forms. Basically, all 3 forms must receive data from the same serial port at the same time. The problem I am facing is that only one form can receive data from the serial port, but the other two forms can't.
I found a question similar to this:
Using same serial port data received event on two different forms
Is that problem similar to mine? If yes, can I know where should I place the sample code in the aforementioned link in my code?
Can someone please help with this? Thanks in advance!
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
Form3 f3 = new Form3();
f3.Show();
Form4 f4 = new Form4();
f4.Show();
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
}
Form2:
public partial class Form2 : Form
{
GMapControl MainMap = new GMapControl();
//Initialise data type for latituide and longitude
double lat, lng;
//Initialise customise marker (plane maker). Declared as m.
GMapMarkerImage m = new GMapMarkerImage(new PointLatLng());
GMapOverlay overlayOne;
public Form2()
{
InitializeComponent();
SuspendLayout();
overlayOne = new GMapOverlay(MainMap, "OverlayOne");
MainMap.MapProvider = GMapProviders.YahooMap;
MainMap.SetCurrentPositionByKeywords("Singapore");
MainMap.MinZoom = 1;
MainMap.MaxZoom = 24;
MainMap.Zoom = 13;
MainMap.CanDragMap = true;
MainMap.DragButton = MouseButtons.Left;
MainMap.Dock = DockStyle.Fill;
MainMap.Manager.Mode = AccessMode.ServerAndCache;
Controls.Add(MainMap);
ResumeLayout(true);
}
public void button1_Click(object sender, EventArgs e)
{
if (!serialPort1.IsOpen) //if serial port is not open
try
{
serialPort1.Open(); //Open Serial Port
if (lat != 0 && lng != 0) //Display marker only when GPS has receive data
{
overlayOne.Markers.Add(m); //Add marker on the position given to the overlayOne layer
MainMap.Overlays.Add(overlayOne); //Add overlayOne layer to the MainMap layer
}
}
catch
{
//A message box will display this message, informing user either a wrong port has been chosen, or have not been plugged in.
MessageBox.Show("There was an error. Please make sure that the correct port was selected, and the device, plugged in.");
}
}
public void button2_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen) // if Serial Port is open
{
serialPort1.Close(); //Close Serial
overlayOne.Markers.Remove(m);
}
}
//When microsoft visual studio receive data
public void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
this.Invoke(new EventHandler(DoUpdate)); //for function DoUpdate
//Pause Microsoft Visual Studio for 100 milliseconds from receiving data,
//to ensure serialPort can be close successfully
Thread.Sleep(100);
}
//Function for updating data. Declared as DoUpdate.
public void DoUpdate(object sender, EventArgs e)
{
string[] c = serialPort1.ReadLine().Split(','); //Stored data seperately by using array & using the Split() function
lat = Convert.ToDouble(c[9]); //Convert Latitude string data to double data
lng = Convert.ToDouble(c[10]); //Convert Longitude string data to double data
//Input lat and lng data in m.
//Updating the position of the marker
m.Position = new PointLatLng(lat, lng);
}
}
Form3:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (!serialPort1.IsOpen) //if serial port is not open
try
{
serialPort1.Open(); //Open Serial Port
//Enable blocks to have colour
// ...
}
catch
{
//A message box will display this message, informing user either a wrong port has been chosen, or have not been plugged in.
MessageBox.Show("There was an error. Please make sure that the correct port was selected, and the device, plugged in.");
}
}
private void button2_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen) // if serial port is open
{
serialPort1.Close(); // Close serial Port
//Clear data in textboxes
FrontSonar.Text = " ";
LeftSonar.Text = " ";
RightSonar.Text = " ";
//Clear colours in the boxes
// ...
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) //When microsoft visual studio receive data
{
this.Invoke(new EventHandler(DoUpdate1)); //To update and ensure sonar data infront of UAV can be displayed without error
this.Invoke(new EventHandler(DoUpdate2)); //To update and ensure sonar data left side of UAV can be displayed without error
this.Invoke(new EventHandler(DoUpdate3)); //To update and ensure sonar data on the right side of UAV can be displayed without error
Thread.Sleep(100);
}
private void DoUpdate1(object s, EventArgs e) //Display for Sonar infront of UAV
{
string[] c = serialPort1.ReadLine().Split(','); //Stored data seperately by using array & using the Split() function
FrontSonar.Text = c[1] + "\n";
double d = Convert.ToDouble(c[1]);
if (d > 500)
{
//Fill blocks with green
this.rectangleShape1.FillColor = System.Drawing.Color.Green;
this.rectangleShape2.FillColor = System.Drawing.Color.Green;
this.rectangleShape3.FillColor = System.Drawing.Color.Green;
}
else
if (d > 400 && d <= 500)
{
//Fill block with Orange colour
this.rectangleShape1.FillColor = System.Drawing.Color.Orange;
this.rectangleShape2.FillColor = System.Drawing.Color.Orange;
//Fill block with Lavender colour
this.rectangleShape3.FillColor = System.Drawing.Color.Lavender;
}
else
if (d <= 400)
{
//Fill block with red colour
this.rectangleShape1.FillColor = System.Drawing.Color.Red;
//Fill block with Lavender colour
this.rectangleShape2.FillColor = System.Drawing.Color.Lavender;
this.rectangleShape3.FillColor = System.Drawing.Color.Lavender;
}
}
private void DoUpdate2(object s, EventArgs e) //Display for Sonar on the left side of UAV
{
string[] c = serialPort1.ReadLine().Split(','); //Stored data seperately by using array & using the Split() function
// ....
}
private void DoUpdate3(object s, EventArgs e) //Display for Sonar on the right side of UAV
{
string[] c = serialPort1.ReadLine().Split(','); //Stored data seperately by using array & using the Split() function
// ...
}
}
Form4: (Still in progress)
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
}

Yes, you can. Below is key points to achieve this:
Open serial port once, your approach if (!port.IsOpened) { port.Open(); } is right, extract this in a static method and call in each form (f2, f3, f4) to avoid copy/paste of this code snippet.
serialPort variable should be shared across all three forms, so the same opened and initialized port instance would be accessible for all forms. Considering code you've provided, create and initialize, open port in Form1 class, then pass initialized instance of serialPort into other form classes via constructor injection, basically add SerialPort port constructor parameter for Form2,3,4 classes and then:
// renamed button1_Click
private void OnSetup(object sender, EventArgs e)
{
this.port = new SerialPort(...);
// TODO: initialize port
Form2 f2 = new Form2(this.port);
f2.Show();
Form3 f3 = new Form3(this.port);
f3.Show();
Form4 f4 = new Form4(this.port);
f4.Show();
}
Then in each form constructor just subscribe to serialPort.DataReceived event and that's it.
public Form2(SerialPort port)
{
port.DataReceived += ...
}
Some recommendations,
Give variables and methods more descriptive names rather than form1, form2, c, d, button2_Click
Avoid magic numbers, extract constants in variables and give descriptive names, for instance there are multiple occurences of 400, 500 magic numbers, it is not clear for what they are.
In comments to a code you saying Pause Microsoft Visual Studio..., microsoft visual studio receives data..., this is not correct, execution of your application (but not Visual Studio) will be paused while Thread.Sleep() and your applciation will receive an incomming serial port data, Visual Studio is just a development environment and in such cases dos not involved in a port communication directly.

Related

How to change the active tab in tabControl with serialPort DatatReceived event?

I have a problem with my C# Windows Form App, i'm trying to change the active tab in tabControl1, it works when I click on the button1 but when I send serial data, the page change, but the program crashes.
The serial data is sent by an Arduino, it only send "S" every 2 seconds.
Here is the code I used to test this :
public partial class Form1 : Form
{
int page = 0;
public Form1()
{
InitializeComponent();
serialPort1.Open();
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
page++;
if (page == 4)
{
page = 0;
}
tabControl1.SelectedIndex = page;
tabControl1.Refresh();
}
private void button1_Click(object sender, EventArgs e)
{
page++;
if (page == 4)
{
page = 0;
}
tabControl1.SelectedIndex = page;
tabControl1.Refresh();
}
}
Is this a bug, or am I doing it the wrong way ?
The DataReceived event is raised on a secondary thread when data is
received from the SerialPort object.
https://msdn.microsoft.com/fi-fi/library/system.io.ports.serialport.datareceived(v=vs.110).aspx
you have to use invoke method to modify the form main thread UI elements.
//Create a delegate
public delegate void ModifyTabPage();
//Create an object in the form for delegate and instatiate with the method which modifies tabpage
public ModifyTabPage myDelegate;
myDelegate = new ModifyTabPage(ModifyTabPageMethod);
public void ModifyTabPageMethod()
{
page++;
if (page == 4)
{
page = 0;
}
tabControl1.SelectedIndex = page;
tabControl1.Refresh();
}
//using invoke access it from the data recived event of your serialize port.
myFormControl1.Invoke(myFormControl1.myDelegate);
This Should work.

How to output data sent through serial port onto a textBox? C# Visual Studio

I'm currently working on a C# application and where I read Serial Data send through the USB port, where this data is to be shown on a textbox then eventually into a database. The code I have right now has it refresh to read serial data coming in every 2 seconds, but I cannot get the data onto the textBox. I'm fairly new to C# development so I am unsure as to what the best way to output my data onto a textbox or how to fix my problem in the first place. My code is below.
public partial class Form1 : Form
{
SerialPort mySerialPort = new SerialPort("COM3");
OleDbConnection connection = new OleDbConnection();
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
if (mySerialPort.IsOpen == false)
{
mySerialPort.Open();
}
}
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
//gets data values from serial port
SerialPort sp = (SerialPort)sender;
string data = sp.ReadExisting();
string time = GetTimestamp(DateTime.Now);
int indata;
long timeStamp;
//parses strings to integers
indata = Int32.Parse(data);
timeStamp = Int64.Parse(time);
//writes to console
Console.WriteLine(indata);
Console.WriteLine(timeStamp);
//writes to text box
textBox1.Text = data;
Thread.Sleep(2000);
}
private void button3_Click(object sender, EventArgs e)
{
mySerialPort.Close();
}
private void label1_Click(object sender, EventArgs e)
{
}
public static string GetTimestamp(DateTime value)
{
return value.ToString("yyyyMMddHHmmss");
}
private void label1_Click_1(object sender, EventArgs e)
{
}
}
The event DataReceived is handled with the method DataReceivedHandler on a different thread than the control textBox1 is created. So when running your program you should have get a System.InvalidOperationException. Which states exactly what I just described.
To get out of this dilemma you can use the Control.BeginInvoke method which would:
Execute the specified delegate asynchronously on the thread that the control's underlying handle was created on.
Basically it would drag the piece of code down to the thread that cretated the control. In this case the main thread. This is how you would use it:
//writes to text box
textBox1.BeginInvoke(new Action(() => { textBox1.Text = data; }));
I hope it helps.

C# - Form2 value to Form1

I'm having trouble passing values ​​entered in form2(citacao) to form1(principal).
Principal.cs (form1)
richEditControl1.Document.AppendText(citacao.valor_edit[0]);
Citacao.cs (form2)
public string[] valor_edit = new string[3];
private void simpleButton2_Click(object sender, EventArgs e)
{
valor_edit[0] = memoEdit1.Text;
valor_edit[1] = comboBox1.SelectedItem.ToString();
valor_edit[2] = textEdit1.Text;
}
But when I click the button nothing happens , the values ​​are not inserted into the richedit I like it.
I already have this on form (Pass DataGrid to ComboBox)
Form1 (principal)
private void barButtonItem1_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
citacao cita = new citacao(this);
cita.Show();
}
form2(citação)
public citacao(principal gridForm)
{
InitializeComponent();
frm1 = gridForm;
}
// LOAD ALL FONTS (Referencias);
private void citacao_Load(object sender, EventArgs e)
{
comboBox1.Items.Clear();
foreach (DataGridViewRow row in frm1.DataGridView1.Rows)
{
comboBox1.Items.Add(row.Cells[0].Value.ToString());
}
comboBox1.SelectedIndex = 0;
}
let's see whether I understood your situation :)
declare your variable in Form 1 as a class variable
private citacao cita;
then initialize it in the button press event
private void barButtonItem1_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
cita = new citacao(this);
// subscribe to the closing event
cita.FormClosing += form_FormClosing;
cita.Show();
}
// when Form 2 will be closed you can execute your important line in the event
void form_FormClosing(object sender, FormClosingEventArgs e)
{
// BUT! you have to use the variable name!
richEditControl1.Document.AppendText(cita.valor_edit[0]);
}
EDIT:
Ok after looking at the entire code:
please remove the button3! and this entire code:
private void button3_Click(object sender, EventArgs e)
{
cita = new citacao(this);
richEditControl1.Document.AppendText(citacao.valor_edit); // this line is the problem!
}
The function AppendText probably needs a string as parameter and you give the entire array!
If you subscribe to the closing event in Form1 / principal and also implement
the event, your data will be transmitted automatically as soon as the Form 2 disappears from the screen :)

How to pop up camera using picture box when button click?

I make a program in C# windows form I have tons of function in my form including two datagrid view that connected to dabase and including a camera that direcly connected to my PC I use AForge dll reference to connect to the camera device I just found the tutorial on youtube and it works perfecly for me, as I stated earlier I have too many programs in one form including that camera and it went out that the camera was need to be resized to a small resolution, so I decided to make a popup button that must show the wider resolution when I click the button on my form.
this is the code for my camera.
//Camera
// get the devices name
private void getCamList()
{
try
{
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
comboBox1.Items.Clear();
if (videoDevices.Count == 0)
throw new ApplicationException();
DeviceExist = true;
foreach (FilterInfo device in videoDevices)
{
comboBox1.Items.Add(device.Name);
}
comboBox1.SelectedIndex = 0; //make dafault to first cam
}
catch (ApplicationException)
{
DeviceExist = false;
comboBox1.Items.Add("No capture device on your system");
}
}
//refresh button
private void refresh_Click(object sender, EventArgs e)
{
getCamList();
}
//toggle start and stop button
private void start_Click(object sender, EventArgs e)
{
if (start.Text == "&Start")
{
if (DeviceExist)
{
videoSource = new VideoCaptureDevice(videoDevices[comboBox1.SelectedIndex].MonikerString);
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
CloseVideoSource();
videoSource.DesiredFrameSize = new Size(160, 120);
//videoSource.DesiredFrameRate = 10;
videoSource.Start();
lblCam.Text = "Device running...";
start.Text = "&Stop";
}
else
{
lblCam.Text = "Error: No Device selected.";
}
}
else
{
if (videoSource.IsRunning)
{
CloseVideoSource();
lblCam.Text = "Device stopped.";
start.Text = "&Start";
}
}
}
//eventhandler if new frame is ready
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap img = (Bitmap)eventArgs.Frame.Clone();
//do processing here
pictureBox1.Image = img;
}
//close the device safely
private void CloseVideoSource()
{
if (!(videoSource == null))
if (videoSource.IsRunning)
{
videoSource.SignalToStop();
videoSource = null;
}
}
//prevent sudden close while device is running
private void Form1_FormClosed(object sender, FormClosingEventArgs e)
{
CloseVideoSource();
}
} }
I also posted a picture so that you have further understanding what I am talking.
as you can see at the lower right corner I have a pop up button there honestly telling you I already tried different methods but nothing works unfotunately I cannot post what I've tried because I created it yesterday and can no longer undo the codes I tried. Any Idea?
Create a new Form
Place a PictureBox on this Form
Add all methods to initialize and get the current frame to the Form (should be refactored to an own class providing an event like FrameChanged giving you the current image)
add a method like to the Form
public void ShowCamPopup(string deviceName)
{
InitializeDevice(string deviceName, int width, int height);
this.Show();
this.BringToTop();
}
You should the really consider to refactor the communication with your cam to an own class which reduces duplicate code and allows you to do performance tweaks (which you will need for sure later) at a single position of your solution.

Visual Studio 2010 C# DataReceived does not seem to trigger

Visual Studio 2010 C# code:
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;
namespace YamanPonics
{
public partial class Form1 : Form
{
string RxString;
//Default SerialPortStatus equals TRUE when first starting up
Boolean serialPortDisconnected = true;
public Form1()
{
InitializeComponent();
//Add available Serial COM ports to combobox
foreach (string ports in System.IO.Ports.SerialPort.GetPortNames())
{
//MessageBox.Show("Serial port avialible" + " " + ports);
comPortCmbBox.Items.Add(ports);
}
}
private void DisplayText(object sender, EventArgs e)
{
serialMsgViewerRchTxt.AppendText(RxString);
MessageBox.Show("Displayed Serial Text!");
}
private void serialPort1_DataReceived (object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxString = serialPort1.ReadExisting();
this.Invoke(new EventHandler(DisplayText));
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//If SerialPort1 IsOpen
if (serialPort1.IsOpen)
{
//Close SerialPort1 communication
serialPort1.Close();
}
}
private void connectDisconnectBtn_Click(object sender, EventArgs e)
{
//Set arduinoComPort value to COM Port value
string arduinoComPort = comPortCmbBox.Text;
//if SerialPortStatus boolean equals FALSE then
if (serialPortDisconnected && (arduinoComPort != ""))
{
//Set serialPort1 BaudRate value to default value of 38400(required for atlas-scientific sensors)
serialPort1.BaudRate = 38400;
//Set serialPort1 Read and Write timeout values
serialPort1.ReadTimeout = 250;
serialPort1.WriteTimeout = 250;
//Set serialPort1 DataBits value
serialPort1.DataBits = 8;
//Open serialPort1 communication
serialPort1.Open();
//Change connectDisconnectBtn text to Disconnect
connectDisconnectBtn.Text = "Disconnect";
//Set serialPortDisconnected to FALSE
serialPortDisconnected = false;
}
else //if SerialPortStatus bollean equals TRUE
{
//Close SerialPort1 communication
serialPort1.Close();
//Set connectDisconnectBtn text to Connect
connectDisconnectBtn.Text = "Connect";
//Set serialPortDisconnected to TRUE
serialPortDisconnected = true;
}
}
private void SendBtn_Click(object sender, EventArgs e)
{
//if serialPort1 IsOpen then
if (serialPort1.IsOpen)
{
serialPort1.Write("{ph}");
}
}
}
}
That code is a simple Serial connect/disconnect and send/receive application. Connect, Disconnect, and send works properly. When my arduino receives a command it sends a response back. My 2010 C# application is not receiving the response in the richtextbox and do not understand why. I can receive a response when I use another serial terminal program so I do know for sure that data is being sent. What am I not doing to successfully receive a response?
Are you sure the serialPort1.DataReceived event is wired up correctly? I see you have the handler method, but I don't see you subscribing to the event.
You need to have this somewhere:
serialPort1.DataReceived += serialPort1_DataReceived;

Categories

Resources