Reading Serial Communication Visual Studios - c#

I need some help with Background worker. I am trying to read data from a serial port (works fine with a button) the problem is that I need to continuously read from the serial port, until someone presses a button (Close button) on the form to stop reading. I tried doing this by adding a loop, but it just ran infinitely and froze up the form. I have the following code, whenever I press the button to read, a file is created, but when I press the close port button,it says
The I/O operation has been aborted because of either a thread exit or
an application request
Any ideas on how to fix this?
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.IO.Ports;
using System.IO;
namespace SerialCommunication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
GetAvaliablePortNames();
}
bool indicator;
StreamWriter sw = new StreamWriter(#"C:\Users\slahiri\Desktop\Data\jumbo.txt");
void GetAvaliablePortNames()
{
string[] Ports = SerialPort.GetPortNames();
cmbPort.Items.AddRange(Ports);
}
private void btnOpen_Click(object sender, EventArgs e)
{
try
{
if (cmbPort.Text == "" || cmbBaud.Text == "")
{
MessageBox.Show("Please select the Port and Baud Rates");
}
else
{
serialPort1.PortName = cmbPort.Text;
serialPort1.BaudRate = Convert.ToInt32(cmbBaud.Text);
serialPort1.Open();
progressBar1.Value = 100;
groupBox2.Enabled = true;
btnRead.Enabled = true;
btnOpen.Enabled = false;
btnClose.Enabled = true;
}
}
catch (UnauthorizedAccessException)
{
txtRead.Text = "Unauthorized Acess";
}
}
private void btnClose_Click(object sender, EventArgs e)
{
serialPort1.Close();
progressBar1.Value = 0;
btnClose.Enabled = false;
btnRead.Enabled = false;
btnOpen.Enabled = true;
indicator = true;
}
private void btnRead_Click(object sender, EventArgs e)
{
if (btnRead.Text == "Read")
{
btnRead.Text = "Stop and Close Port";
progressBar1.Maximum = 1000;
progressBar1.Value = 0;
backgroundWorker1.RunWorkerAsync(progressBar1.Maximum);
indicator = false;
}
else
{
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
int max = (int)e.Argument;
int n = 0;
indicator = false;
do
{
//write to serial writer
sw.WriteLine(serialPort1.ReadLine());
if (backgroundWorker1.CancellationPending)
{
sw.Flush();
sw.Close();
e.Cancel = true;
break;
}
// backgroundWorker1.ReportProgress(n++);
}
while (indicator ==false);
}
catch (TimeoutException)
{
//Close Serial Writer & Messagebox
//txtRead.Text = "Time Out!";
MessageBox.Show("TimeOut Exception");
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnRead.Text = "Read";
//close serial writer
}
}
}

Since you have a do-while construct you evaluate the condition at the END!
So when you hit the Close button and close the SerialPort the backgroundworker is still active and running in the background trying to read from the SerialPort. It enters the do compartment and tries to read from a closed port, which is like running agains a closed door :) this leads to the exception.
You could solve it by
1) putting the while-evaluation on top and get rid of the do statement (making it a simple while-loop). This way the serialPort.ReadLine will not be executed anymore, because you set indicator = true; when hitting the close button.
May be in this case you should put the setting of indicator as the first line before closing the port:
private void btnClose_Click(object sender, EventArgs e)
{
try
{
indicator = true;
serialPort1.Close();
Or
2) put an extra if clause that makes sure to read only if the port is open!
if (serialPort1.IsOpen)
{
sw.WriteLine(serialPort1.ReadLine());
}

Related

SerialPort.GetPortNames() comparison for serial ports in C#

I am testing a real-time port view for serial port.
The Form1 and debug state with always false is shown below.
When Form1 is created, the COM port list is stored in recordedPorts and timer1_Tick event is generated every 100ms, the current COM port list is read and stored in presentPorts and compared with recordedPorts. If you look at the debug state picture, you can see that the result value string[] each of GetPortNames() method is the same.
I want to display COM ports in comboBox1 in real time.
However, it could not be displayed in the comboBox1.
There was a problem in string operation, so timer1_Tick event could not be operated normally.
The first question is to know why string real-time comparison is always false,
and the second is whether there is any other way to display the serial port in real time.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace TestSerial
{
public partial class Form1 : Form
{
string[] recordedPorts, presentPorts;
string str;
public Form1()
{
InitializeComponent();
recordedPorts = SerialPort.GetPortNames();
foreach (string PortName in recordedPorts)
{
comboBox1.Items.Add(PortName);
}
}
private void button2_Click(object sender, EventArgs e)
{
if(serialPort1.IsOpen == true)
{
serialPort1.Close();
textBox1.Text += "disconnected." + Environment.NewLine;
}
else
{
textBox1.Text += "already disconnected." + Environment.NewLine;
}
}
private void button1_Click(object sender, EventArgs e)
{
if(serialPort1.IsOpen == false)
{
serialPort1.PortName = comboBox1.SelectedItem.ToString();
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.StopBits = StopBits.One;
serialPort1.Parity = Parity.None;
//serialPort1.Open();
try
{
serialPort1.Open(); //serial port open!!!
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
return;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
textBox1.Text += "connected." + Environment.NewLine;
serialPort1.WriteLine("abcd\r\n");
}
else
{
textBox1.Text += "already connected." + Environment.NewLine;
}
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
str = serialPort1.ReadExisting();
if(str.Length > 8)
{
textBox1.SelectedText += str + Environment.NewLine;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
presentPorts = SerialPort.GetPortNames();
if (presentPorts.Count() == 0)
{
//if(comboBox1.Items.Count != 0) comboBox1.Items.Clear();
recordedPorts = presentPorts;
return;
}
if (recordedPorts != presentPorts)
{
comboBox1.DataSource = presentPorts;
recordedPorts = presentPorts;
}
}
}
}
The debug state that is always false is as follows.
Thanks to Klaus Gütter.
I resolved this question by comparing the content of the arrays instead of the array references.
Change it to the code below and it works normally.
if (!recordedPorts.SequenceEqual(presentPorts))
//if (recordedPorts != presentPorts)
{
comboBox_port.DataSource = presentPorts;
recordedPorts = presentPorts;
}

Capturing serial welcome message when connecting in c#

I am trying to write a program that communicates with a controller. The controller is supposed to send a "welcome" message when a connection is successfully established and, in fact, it does when I connect using a communications software. However, using the .NET code below, I never see the welcome message. Beyond that, it works. How can I capture this message. It seems to be sent the moment the connection is established.
Again, I am able to communicate fine with the controller after connection but I simply cannot seem to get the welcome message that is sent a the moment the connection is opened.
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public delegate void AddDataDelegate(String myString);
public AddDataDelegate myDelegate;
SerialPort sp;
public Form1()
{
InitializeComponent();
}
public void AddDataMethod(String myString)
{
richTextBox1.AppendText(myString);
richTextBox1.SelectionStart = richTextBox1.Text.Length;
richTextBox1.ScrollToCaret();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
sp = new SerialPort(comboBox1.SelectedItem.ToString(),Int32.Parse(comboBox2.SelectedItem.ToString()));
sp.DataReceived += SerialPort_OnDataReceived;
sp.Close();
sp.Open();
richTextBox1.AppendText("open\n");
button2.Enabled = true;
button3.Enabled = true;
}
catch (Exception ex)
{
richTextBox1.AppendText(ex.Message);
}
}
void SerialPort_OnDataReceived(object sender,SerialDataReceivedEventArgs args)
{
SerialPort sp = sender as SerialPort;
string s = sp.ReadExisting();
richTextBox1.Invoke(this.myDelegate, new Object[] { s });
}
private void button2_Click(object sender, EventArgs e)
{
sp.WriteLine(textBox1.Text);
textBox1.Text = "";
}
private void button3_Click(object sender, EventArgs e)
{
sp.DiscardOutBuffer();
sp.DiscardInBuffer();
sp.Close();
richTextBox1.AppendText("\nclosed\n");
}
private void Form1_Load_1(object sender, EventArgs e)
{
this.myDelegate = new AddDataDelegate(AddDataMethod);
string[] Ports = SerialPort.GetPortNames();
comboBox2.SelectedIndex = comboBox2.Items.Count - 1;
Array.Sort(Ports, (a, b) => string.Compare(a.Substring(3).PadLeft(3, '0'), b.Substring(3).PadLeft(3, '0')));
foreach (string port in Ports)
{
comboBox1.Items.Add(port);
}
comboBox1.SelectedIndex = 0;
}
}
}
I worked it out. Required a slight delay between connection and trying to pull data from the port.

C# Ping -t stopping by button

I have little problem with stopping infinite Pinging.
If you see in picture I ping IP 127.0.0.1 it has infinite ping ( -t ).
And I want do that when I Click Stop! button then it stops pinging.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Management;
namespace PingProgramm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread th;
private void button1_Click(object sender, EventArgs e)
{
th = new Thread(thread1);
th.Start();
}
public void thread1()
{
try
{
string command = "/c ping -t " + textBox1.Text;
ProcessStartInfo procStartInfo = new ProcessStartInfo("CMD", command);
Process proc = new Process();
proc.StartInfo = procStartInfo;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardInput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
catch (Exception)
{
//if an error occurs with in the try block, it will handled here.
}
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
string newLine = e.Data.Trim() + Environment.NewLine;
MethodInvoker append = () => richTextBox1.Text += newLine;
richTextBox1.BeginInvoke(append);
}
}
bool firstTime = true;
private void textBox1_Click(object sender, EventArgs e)
{
if (firstTime)
{
firstTime = false;
textBox1.Clear();
}
}
private void button2_Click(object sender, EventArgs e)
{
}
}
}
Best wishes
KLDesigns,
The simplest thing that might work in your current code is to get hold of your Process instance in the DataReceived event and cancel the process there (or send a Ctrl+C on the stdin).
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (stop)
{
// sender is our process instance
// so we can cast that safely here
var proc = (Process) sender;
// brutally kill it
proc.Kill();
// or more gently, send a ctrl+C
// http://stackoverflow.com/a/285041/578411
proc.StandardInput.Close();
}
if (e.Data != null)
{
string newLine = e.Data.Trim() + Environment.NewLine;
MethodInvoker append = () => richTextBox1.Text += newLine;
richTextBox1.BeginInvoke(append);
}
}
You can set the boolean stop in your click event handler:
bool stop = false;
private void button2_Click(object sender, EventArgs e)
{
stop = true;
}
Keep in mind that if you want to keep control over object instances you create consider keeping a reference to them. As you create the Process inside the thread your form can't reach it any more. If you would have made the proc an member of your form you could have called proc.StandardInput.Close() from your click event.

Application crash when close com port in a background worker - C# application?

I had done a quick-search and still cant find the answer for my question .
Serial port variable
int close;
SerialPort _serialPort = new SerialPort("COM1", 1200, Parity.None, 8, StopBits.One);
Serial port delegate code
private void si_DataReceived(string data)
{
if (close == 1)
{
string d1 = data.Trim().Replace("TT", "");
d1 = d1.Replace("Tl3", "");
txtCan.Text = d1;
}
else
{
return;
}
}
private delegate void SetTextDeleg(string text);
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = _serialPort.ReadLine();
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
}
Connect button code
private void button4_Click(object sender, EventArgs e)
{
if (button4.Text == "Close Connection")
{
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.MarqueeAnimationSpeed = 0;
close=0;
try
{
string d1 = txtCan.Text;
double r1 = Convert.ToDouble(d1) * 10;
txtCan.Text = Math.Round(r1, 3).ToString();
button4.Text = "Open Connection";
button1.Enabled = true;
readOnly(true);
}
catch (Exception ex)
{
button4.Text = "Open Connection";
button1.Enabled = true;
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.MarqueeAnimationSpeed = 0;
MessageBox.Show("Cant connect.");
}
}
else
{
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.MarqueeAnimationSpeed = 30;
close = 1;
txtCan.Text = "";
txtCan.Focus();
readOnly(false);
button1.Enabled = false;
button4.Text = "Close Connection";
try
{
if(!_serialPort.IsOpen)
{
_serialPort.Handshake = Handshake.None;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
_serialPort.Open();
}
}
catch
{
button4.Text = "Open Connection";
button1.Enabled = true;
readOnly(true);
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.MarqueeAnimationSpeed = 0;
MessageBox.Show("Cant connect.");
}
}
}
My solution to close a com port, but it will fail if I re-open a form in countable times (like twice or triple times then it will crash)
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (_serialPort.IsOpen)
{
e.Cancel = true;
Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit));
CloseDown.Start();
}
}
private void CloseSerialOnExit()
{
try
{
backgroundWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
}
this.BeginInvoke(new EventHandler(NowClose));
}
private void NowClose(object sender, EventArgs e)
{
this.Close(); //now close the form
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
_serialPort.Close();
}
string data = _serialPort.ReadLine();
There is no lack of potential trouble with this statement. You have a pretty nasty failure-mode on your hands when this call doesn't complete. It doesn't have to, you could turn off the serial device at just the wrong time, jerk the cable, get the line terminator corrupted and you'll have a pretty big headache.
The SerialPort.Close() method cannot complete until any of the event handlers stop running. This can significantly increase the odds for deadlock. Using the ReadLine() method is fine, but then you also have to set the ReadTimeout property to, say, 10 seconds so you can be sure that accidents don't turn into undebuggable problems. Let the TimeoutException either terminate your program or set a "serial port is dead" status variable.
Further improve the odds for success by disassociating the lifetime of the SerialPort with the lifetime of your form. In general the only sensible thing to do is to create the instance at program startup and not close it until your program terminates. Just keep it in a separate class, it can be static to make it easy to use.
And, unintuitively, it is now no longer important to call Close() at all. The finalizer will take care of it.
Also make sure that, if you use a USB emulator, to never disconnect it without going through the Safely Remove Hardware tray icon. USB drivers generally deal with a surprise removal very poorly. Some are so poor that they make the device disappear even though you have it opened. And trying to close it always fails, you cannot cleanly exit your program anymore.

C# how to save data without repeating itself

This program is used to display the data and store the data into a txt file using the input from the pic18f4550.
when the GUI received the input data is '1 ', the GUI should display the data and store the data into a txt file. data can be saved, but the data are keep repeating itself without stopping if the input is still in a state of '1 '.
how should i do, if i want to store the data just once even the input still '1'?
Here is my 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;
using System.IO;
namespace Monitoring_System
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
// Create the USB reference device object (passing VID and PID)
theUsbDemoDevice = new usbDemoDevice(0x04D8, 0x003F);
// Add a listener for usb events
theUsbDemoDevice.usbEvent += new usbDemoDevice.usbEventsHandler(usbEvent_receiver);
// Perform an initial search for the target device
theUsbDemoDevice.findTargetDevice();
}
// Create an instance of the USB reference device
private usbDemoDevice theUsbDemoDevice;
// Listener for USB events
private void usbEvent_receiver(object o, EventArgs e)
{
// Check the status of the USB device and update the form accordingly
if (theUsbDemoDevice.isDeviceAttached)
{
// Device is currently attached
// Update the status label
usb_status.Text = "Status : USB Device Connected";
}
else
{
// Device is currently unattached
// Update the status label
usb_status.Text = "Status : USB Device Unplugged";
cr1v.Visible = false;
cr1i.Visible = false;
cr2v.Visible = false;
cr2i.Visible = false;
cr3v.Visible = false;
cr3i.Visible = false;
tr1v.Visible = false;
tr1i.Visible = false;
tr2v.Visible = false;
tr2i.Visible = false;
tr3v.Visible = false;
tr3i.Visible = false;
}
}
private void button_exit_Click(object sender, EventArgs e)
{
this.Hide();
Form4 f2 = new Form4();
f2.ShowDialog();
}
private void timer1_Tick_1(object sender, EventArgs e)
{
if(theUsbDemoDevice.isDeviceAttached)
{
// Read the push button state
bool sw1 = theUsbDemoDevice.sw1();
if (sw1 == true)
{
cr1i.Visible = false;
cr1v.Visible = true;
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"D:\Desktop\log data.txt", true))
{
file.WriteLine("Class Room 1 in use");
file.Close();
}
}
else if (sw1 == false)
{
cr1i.Visible = true;
cr1v.Visible = false;
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"D:\Desktop\log data.txt", true))
{
file.WriteLine("Class Room 1 vacant");
file.Close();
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
Form5 f2 = new Form5();
f2.ShowDialog();
}
}
}
It looks like you are using a timer. Every tick your timer is writing to a file. You need to re-work your logic to either not include a timer. Or, disable it after a write, and re-enable it on another event.

Categories

Resources