Currently, when I press the button, it is supposed to restart one of our servers and upon completion return the result. The command runs successfully but after running it, the client crashes because technically the command never really finishes.
After running the command, the server starts running and it will keep outputting server information in the console about the server. How would i make it so that it stops by default after like 15 seconds, or when the output stream is returning emptiness.
I am new to C# so not sure how to approach this.
private void button1_Click(object sender, EventArgs e)
{
using (var client = new SshClient("IP", "USER", "PASS"))
{
label1.Text = "Status: Initiated restart";
client.Connect();
var cmd = client.RunCommand("./server restart && ./server2 restart");
var result = cmd.Execute();
client.Disconnect();
label1.Text = "Status: Restart completed";
}
}
This is my code. Normally, if you type a command (like LS) it will return the output, then let your type again. But in this case, the server keeps running so it will not let you type anything again, thus its not recognized as the command has finished, as it is still running.
I'm not quite sure if I get you right, but I would wrap try and catch around the problematic code, especially if you don't care about the output in that case.
private void button1_Click(object sender, EventArgs e)
{
using (var client = new SshClient("IP", "USER", "PASS"))
{
label1.Text = "Status: Initiated restart";
try
{
client.Connect();
var cmd = client.RunCommand("./server restart && ./server2 restart");
var result = cmd.Execute();
client.Disconnect();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
label1.Text = "Status: Restart completed";
}
}
Related
So I am using c# windows form with visual studio to query an access database.
When I run with debugger and stop the application from within visual studio there is no problem, however when I run WITHOUT debugger, query the database and then close using X, the process which appears under "Apps" in Task manager becomes a background process. I can have multiple instances of this process if I run the application numerous times.
I would appreciate any information on this, Thanks!
Here is the code I am using.
private void BtnSendQuery_Click(object sender, EventArgs e)
{
ReadDatabase();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var x = MessageBox.Show("Are you sure you want to exit? ", "Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (x == DialogResult.No)
{
e.Cancel = true;
}
else
{
e.Cancel = false;
}
}
private void ReadDatabase()
{
string CONNECTION_STR = #"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source = C:\\Users\\***\\Documents\\db_folder\\access_db.accdb;
Persist Security Info = False";
string query = ""; // query string
OleDbConnection DB_CONNECTION = null;
try
{
DB_CONNECTION = new OleDbConnection(CONNECTION_STR);
DB_CONNECTION.Open();
query = TbInputQuery.Text;
var command = new OleDbCommand(query, DB_CONNECTION);
var str = new StringBuilder();
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
str.AppendLine(reader["ID"].ToString());
}
TbOutputTable.Text = str.ToString();
}
DB_CONNECTION.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (DB_CONNECTION != null)
{
DB_CONNECTION.Close();
}
}
}
}
As general rule, both your connection and cmdSQL or reader should be in a using block.
While your reader is in a using block, the ALL important connection object is not.
In fact, once beyond the using block for connection? You could get away not even having using blocks for the command and reader object.
And even if a trapped error, or UN-trapped error occurs? The using block WILL ALWAYS clean up the connection.
So, for command and reader - not end of world for using block.
But, for connection? yes, always do that.
Project->settings - I would use the connection builder for the connection string - not put in code.
eg this one:
Then use advanced, and make sure you choose ACE (for accdb) or JET (for mdb)
So this:
So, with above setting, then we have ONE spot in the system - never typing connecting string by hand or having to place in the code (makes change of connection very hard).
Also, don't use "any cpu" force the project to x86 for using Access x32
(or if using x64, then force project to that).
So, code say like this:
private void ReadDatabase()
{
string CONNECTION_STR = Properties.Settings.Default.AccessDB;
string query = ""; // query string
try
{
using (OleDbConnection DB_CONNECTION = new OleDbConnection(CONNECTION_STR))
{
using (OleDbCommand command = new OleDbCommand(query, DB_CONNECTION))
{
DB_CONNECTION.Open();
var str = new StringBuilder();
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
str.AppendLine(reader["ID"].ToString());
}
TbOutputTable.Text = str.ToString();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
}
}
Note in above - don't really care about the catch block - as long as the using block for the connection is built - it gets cleaned up no matter what - and even if no try/catch, or if in fact you have one!!
And if a error trigger - still again, note how we do NOT have to clean up, or close the connection.
I have this Code to Get a table Data From SQL Server:
public static System.Data.Linq.Table<Equipment> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
I Have a Button to call this Function :
private void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = GetEquipmentTable();
}
My Problem is :When I Disable Communication Between my App and SQL Server Machine and then click this button, It takes a while to throw an Exception that Connect to Database is impossible!!!! My major problem is that my app freezed till this Exception accrued.
Did I missed something ?
Update 1 :
I used async and wait base on Rahul solution
public static async Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
private async void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = await GetEquipmentTable();
}
but it still wait for this line of code :
return dc.GetTable<Equipment>();
and UI freezes as well.
I think dc.gettable<> is not waitable or somthing else !!??
When I Disable Communication Between my App and SQL Server Machine and
then click this button
That's obvious right since it tries to connect to the machine (within the Timeout mentioned in connection string) and then throws the exception back once it finds that the server isn't reachable.
major problem is that my app freezed till this Exception accrued
Probably in that case make the method as async method like
public static async Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
Your event handler
private async void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = await GetEquipmentTable();
}
You have two problems, the app freezing is because you are not using asynchronous programming.
The delay before the connection exception is because the client side app waits until the connection timeout timer finishes (30 seconds default).
Try using async await on your database calls to free up the UI.
Try changing the connection timeout to 5 seconds in the connection string.
Change in connection string:
"Data Source=...;Connect Timeout=5"
Use await as in the answer from Rahul. +1
You could also test a simple SqlConnection.Open
private static bool OpenSqlConnection(string connectionString)
{
bool return = false;
try
{
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
return = true;
}
catch (Exception ex)
{
return = false;
}
finally
{
connection.Close();
}
return return;
}
Could use SqlConnection.OpenAsync.
SqlConnection con = new SqlConnection("connection string");
bool resp = false;
try
{
con.OpenAsync();
resp = true;
}
catch (SqlException ex)
{
//use the ex message
resp = false;
}
catch (Exception ex)
{
resp = false;
}
finally
{
con.Close();
}
I am making a bulk mail sender which will take mail addresses from DB. All is okay, test mails are sending but the success message is showing only after all the mails are sent. I want a message box or a progress box to count the mails that are passing. Help me to add a message pomp to count the mails have been sending. Here the Code I am using for sending mails, please write me the code for the message box to show the count -
private void btnSendEmail_Click(object sender, EventArgs e){
string subject = txtSubject.Text;
string message = txtMessage.Text;
if (!txtFile.Text.Equals(String.Empty))
{
if (System.IO.Directory.GetFiles(txtFile.Text).Length > 0)
{
foreach (string file in System.IO.Directory.GetFiles(txtFile.Text))
{
}
}
else
{
}
}
var con = "Data Source=Ashiq-pc;Initial Catalog=OfferMails;Integrated Security=True;MultipleActiveResultSets=True";
List<EmailModel> emailList = new List<EmailModel>();
using (SqlConnection myConnection = new SqlConnection(con))
{
string oString = "Select * from tbl_MailAdd where Flag=#Flag";
SqlCommand oCmd = new SqlCommand(oString, myConnection);
oCmd.Parameters.AddWithValue("#Flag", true);
myConnection.Open();
using (SqlDataReader oReader = oCmd.ExecuteReader())
{
while (oReader.Read())
{
EmailModel emailModel = new EmailModel();
emailModel.ID = Convert.ToInt16(oReader["ID"]);
emailModel.EmailAdd = oReader["EmailAdd"].ToString();
emailModel.Flag = Convert.ToBoolean(oReader["Flag"]);
emailList.Add(emailModel);
}
myConnection.Close();
}
}
//return matchingPerson;
foreach (EmailModel email in emailList)
{
try
{
SmtpClient client = new SmtpClient("smtp.gmail.com");
client.Port = 587;
client.EnableSsl = true;
client.Timeout = 100000;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("my mail", "my pass");
MailMessage msg = new MailMessage();
msg.To.Add(email.EmailAdd);
msg.From = new MailAddress("my from name");
msg.Subject = subject;
msg.Body = message;
if (!txtFile.Text.Equals(String.Empty))
{
if (System.IO.Directory.GetFiles(txtFile.Text).Length > 0)
{
foreach (string file in System.IO.Directory.GetFiles(txtFile.Text))
{
//Add file in ListBox.
listAttch.Items.Add(file);
//System.Windows.Forms.MessageBox.Show("Files found: " + file, "Message");
Attachment data = new Attachment(file);
msg.Attachments.Add(data);
}
}
else
{
//listBox1.Items.Add(String.Format(“No files Found at location : {0}”, textBox1.Text));
}
}
//Attachment data = new Attachment(textBox_Attachment.Text);
//msg.Attachments.Add(data);
client.Send(msg);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//for (int i = 0; i < emailList.Count; i++)
//{
// MessageBox.Show("i++");
//}
MessageBox.Show("Successfully Sent Message.");
}
First, let me just say that asking for someone to write this code for you is a bit frowned upon here. But I know what you're asking so I'm willing to help out a bit.
Firstly, a message box by itself isn't going to work for this, because a message box ends up stopping the thread where it is until a the DialogResult event is handled. So, for that being said, you will probably want to build another form (I am assuming that you're doing this with Windows Forms here.) to do the progress for you. If you want it to be a counter, then you could do it using a label that is changing its text as each mail is sent.
So, with that being said, however, if you're doing this with a Windows Form, the issue you will run into is the form will never update until after your
foreach loop finishes. This is because of the way that C# handles thread usage.
For what you want to accomplish, you'll need to utilize the BackgroundWorker. This allows you to run cumbersome operations asynchronously.
Here is an example that you could use to get your system working:
//used to be a counter for your progress
int i_counter = 0;
//create a background worker instance
public BackgroundWorker bg_worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
//set this to true if you want to have an event where you can cancel the background task
bg_worker.WorkerSupportsCancellation = true;
//this is needed to actually show your progress, allows the background worker to report it is working
bg_worker.WorkerReportsProgress = true;
//assigns the "DoWork" and "ProgressChanged" Handlers to the background worker.
bg_worker.DoWork += new DoWorkEventHandler(bg_worker_DoWork);
bg_worker.ProgressChanged += new ProgressChangedEventHandler(bg_worker_ProgressChanged);
}
//Mail method
public void MailerMethod()
{
//all of the things you want to happen for your mailing methods
foreach(//your loop stuff in here)
{
//THIS NEEDS TO HAPPEN TO CAUSE THE COUNTER TO UPDATE
bg_worker.ReportProgress(i_counter);
}
}
//the stuff that you want done in the background
//fires when "RunAsync" is called by BackgroundWorker object.
private void bg_worker_DoWork(object sender, DoWorkEventArgs e)
{
//IN HERE IS WHERE YOU WANT YOUR EMAIL STUFF TO HAPPEN
bg_worker = sender as BackgroundWorker;
MailerMethod();//or just all of your mailing code, it looks nicer like this though
}
//fires when worker reports the progress has changed
//caused by "ReportProgress" method
private void bg_worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lb_counter.Text = Convert.ToString(i_counter);
}
//this is what will happen when the worker is done.
//you can have it do a alot of things, such as write a report, show a window, etc.
private void bg_worker_RunWorkComplete(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("DONE!", "DING DING!");
Application.Exit();
}
//button click event to start this shindig
private void bt_start_Click(object sender, EventArgs e)
{
//makes sure the background worker isn't already trying to run
if (!bg_worker.IsBusy)
{
//calls the DoWork event
bg_worker.RunWorkerAsync();
bt_start.Visible = false;
}
}
May I direct you here for the official MDSN documentation.
And here for a basic tutorial on how to set up a BackgroundWorker.
Hope this helps, let me know how it goes.
Use a Progress bar with its Position property set to zero, Max property set to the number of emails you are sending and the Step property set to 1, unless you want to step every 10 or so emails then you would use % 10 in your loop to increase the progress. In your loop simply increase the position of the ProgresBar or call Step().
I want to synchronize my local and web database so i have written a stored procedure using linked server. My stored procedure executes fine and data synchronization is successful but the procedure takes around 7-10 minutes to get executed. The exact timing cannot be determined. So whenever the procedure runs on my windows application then the page seems as if it has become unresponsive though the process is still going on.
So i am having a "Data Sync" button on my page on click of which i want the progress bar to display the progress of the stored procedure. For the time being I am taking the average of last few execution timings to define the time duration for which the stored procedure runs. Now the problem is that when i click on the data sync button then the progress bar doesn't work. Kindly help me with this issue.
My code is as follows:-
namespace RMS
{
public partial class DataSync : Form
{
connection con = new connection();
SqlCommand cmd = new SqlCommand();
static int rowCount;
static int syncTime;
static int timeSlice;
public DataSync()
{
InitializeComponent();
}
private void btnDataSync_Click(object sender, EventArgs e)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
try
{
con.GetConnectLive();
con.GetConnect();
if (con.CnLive.State == ConnectionState.Open)
{
MessageBox.Show("Connection to Live Server Successful!!!...Data Synchronisation may take several minutes so do not cancel the operation while in execution mode");
btnDataSync.Enabled = false;
btnDataSync.Text = "Please Wait...";
string Str = "RMS_LocalToLive";
cmd = new SqlCommand(Str, con.Cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 1200;
rowCount = cmd.ExecuteNonQuery();
if (rowCount > -1)
{
MessageBox.Show("Total no. of rows synchronised = " + rowCount);
btnDataSync.Text = "Success";
}
else
{
MessageBox.Show("Data Synchronisation couldn't be completed because of connection problem... Please try again!!!");
}
}
else
{
MessageBox.Show("Unable to connect to Live Server...Please check your internet connection and try again!!!");
}
con.GetDisConnect();
con.GetDisConnectLive();
}
catch (Exception ex)
{
MessageBox.Show("Please check your internet connection and try again!!!");
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
con.GetConnect();
string Str = "RMS_DataSyncTime";
cmd = new SqlCommand(Str, con.Cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 1200;
syncTime = Convert.ToInt32(cmd.ExecuteScalar().ToString());
timeSlice = syncTime / 100;
con.GetDisConnect();
}
catch (Exception ex)
{
MessageBox.Show("Unable to retrieve last Data Synchronisation Timing");
}
for (int i = 1; i <= synctime; i=i+timeslice)
{
Thread.Sleep(timeslice);
// Report progress.
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString() + "% Completed";
}
private void DataSync_Load(object sender, EventArgs e)
{
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgse)
{
}
}
}
The main issue here is that, while you are executing your progress bar updates in the BackgroundWorker's thread, the ReportProgress() updates never make it to the UI thread, because you've blocked that thread with the main SQL operation.
Instead of doing that, you should do something more like this:
private void btnDataSync_Click(object sender, EventArgs e)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
btnDataSync.Enabled = false;
btnDataSync.Text = "Please Wait...";
bool success = false;
try
{
// Execute the query asynchronously
success = await Task.Run(() => ExecuteLocalToLive());
}
catch (Exception ex)
{
MessageBox.Show("Please check your internet connection and try again!!!");
}
btnDataSync.Enabled = true;
btnDataSync.Text = success ? "Success" : "Failure";
}
private bool ExecuteLocalToLive()
{
bool success = false;
con.GetConnectLive();
con.GetConnect();
if (con.CnLive.State == ConnectionState.Open)
{
MessageBox.Show("Connection to Live Server Successful!!!...Data Synchronisation may take several minutes so do not cancel the operation while in execution mode");
string Str = "RMS_LocalToLive";
cmd = new SqlCommand(Str, con.Cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 1200;
rowCount = cmd.ExecuteNonQuery();
if (rowCount > -1)
{
MessageBox.Show("Total no. of rows synchronised = " + rowCount);
success = true;
}
else
{
MessageBox.Show("Data Synchronisation couldn't be completed because of connection problem... Please try again!!!");
}
}
else
{
MessageBox.Show("Unable to connect to Live Server...Please check your internet connection and try again!!!");
}
con.GetDisConnect();
con.GetDisConnectLive();
return success;
}
I have rearranged the code that handles the button state and text, so that it's still executed in the UI thread where it belongs, even though the method itself is not. You also never appeared to set the button back to the enabled state; it's not clear to me whether that was intentional or not, so I went ahead and added a line to do that.
Finally, I will strongly recommend you figure out a better way to report status to the user than the calls to MessageBox.Show() you have now. The biggest issue is that you don't even start doing any work until after the user dismisses the initial message, which immediately puts your progress bar out of sync with the actual work. But it's also better to keep all your UI in the UI thread, and to keep UI separate from non-UI logic (i.e. the SQL operation).
I'm working on a project that involves my client software sending data to a Arduino microcontroller, AtMega32U4, through serial communication. I've looked through many answered questions so far yet none of them were specific to my problem. However, I believe my problem may be limited to threading issues or Arduino autoreset problems.
Code 1:
public MainForm()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.DtrEnable = true;
//serialPort1.RtsEnable = true;
}
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + #"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + #"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
//serialPort1.Close();
//System.Threading.Thread.Sleep(1000);
if (serialPort1.IsOpen && !doubleClick)
{
serialPort1.Close();
System.Threading.Thread.Sleep(2000);
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
}
else
{
if (!serialPort1.IsOpen)
{
try
{
serialPort1.Open();
doubleClick = true;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine('^');
//button3.Enabled = true;
}
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//System.Threading.Thread.Sleep(1000);
readData = serialPort1.ReadLine();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke( new EventHandler (write_serialPort1));
}
}
In during the debugging of code 1, the event handler (serialPort1_DataReceived) never gets called. In this process, somehow button3_click gets called twice as the console outputs '^' twice. Afterwards, the client stalls since there is nothing beind received. Keep in mind that the Arduino will respond with an ampersand ('&') once it has received the circumflex ('^'). The Arduino code has been tested on the Arduino IDE and appears to be working fine. I believe the problem with button3_click being called twice comes from the button3_down and button3_up.
However, I was able to bypass this issue with Code 2. But also hit another brick wall.
Code 2 :
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + #"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + #"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
serialPort1.Close();
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
if (serialPort1.IsOpen)
{
System.Threading.Thread.Sleep(2000);
using (serialPort1)
{
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("^");
serialPort1.Close();
System.Threading.Thread.Sleep(5000);
}
}
else
{
button3.Enabled = true;
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(10000);
/*if (!serialPort1.IsOpen)
{
serialPort1.Close();
System.Threading.Thread.Sleep(10000);
serialPort1.Open();
System.Threading.Thread.Sleep(10000);
}*/
//serialPort1.Open();
//using (sp)
using (serialPort1)
{
serialPort1.Open();
System.Threading.Thread.Sleep(5000);
readData = serialPort1.ReadExisting();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke(new EventHandler(write_serialPort1));
}
}
}
In Code 2, the event handler does get called and the button3_click only runs once. But when it tries to open the port, it returns the error 'Access to Port X denied'. Furthermore, I wish I didn't have to close and open the ports like this, but when the event handler is called (in an earlier code) it returned the error that the COM Port was not opened. In order to satisfy that error, I had to close it and reopen it during button3_click and event handling.
I've added a lot of delay in the code after I read about many problems dealing with the threading issues with serial communication. I had even tried a minute delay in hopes of a thread ending to solve the problem. However, no luck there.
I also specified my serial port in the MainForm designer instead of declaring it in the code (At first I did both and realized it was redundant). I'm not sure if this contributes to the problem, but I've seen examples of both being used.
Lastly, it could definitely deal with the Arduino auto resetting everytime a serial connection has been made (eg. opening and closing a port). In summary, it seems be sending data through serial, but unable to read the incoming data from serial.
Thank you for reading this and if someone could point me in the right direction, it would be very much appreciated.
Edit #1: Even after using BeginInvoke in Code 1, it still deadlocks because the event handler was never called.
Edit #2: Edits to Code 1 as per newbie's suggestions.
Edit #3: Added mainform initialization and updated Code 1 to current state.
Edit #4: Deleted (Commented out) the sleep at the event handler. I was sleeping during the event handler, thus I couldn't receive anything that the microcontroller would send to me. Code works fine as expected now.
Make sure you are using COM1, if you do not COM1 serial port,
change through Computer -> Device Manager -> Ports (COM & LPT) ->
Select the COM to be changed -> Port Settings -> Advanced -> ComPort Number -> select COM1.
Make sure that you have installed jumper / connect with a screwdriver
between pin2 and pin3 of COM1.
Add button1 and textBox1 to Form and run this program
using System;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.Text;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
const int MAX_BUFFER = 100;
int i = 0;
byte[] DataReceived = new byte[MAX_BUFFER];
SerialPort serialPort = new SerialPort();
public Form1() {
InitializeComponent();
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
// wait data ready
Thread.Sleep(500);
// while data ready in buffer
while (serialPort.IsOpen && serialPort.BytesToRead > 0) {
// read data serial
DataReceived[i] = Convert.ToByte(serialPort.ReadByte());
// counter data
i++;
// reset conter if more then maxvalue
if (i >= MAX_BUFFER) {
i = 0;
}
}
if (i == 1 && DataReceived[0] == ASCIIEncoding.ASCII.GetBytes("^")[0]) {
this.textBox1.Invoke(new Action(() => {
this.textBox1.Text = ASCIIEncoding.ASCII.GetString(DataReceived, 0, 1);
}));
}
}
public void InitSerialPort() {
serialPort.PortName = "COM1";
serialPort.BaudRate = 9600;
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.ReceivedBytesThreshold = 1;
}
private void Form1_Load(object sender, EventArgs e) {
// initialize serial port
InitSerialPort();
// assure port is closed before open it
if (serialPort != null && serialPort.IsOpen) {
serialPort.Close();
}
serialPort.Open();
}
private void button1_Click(object sender, EventArgs e) {
if (serialPort.IsOpen) {
serialPort.Write("^");
// wait data sent
Thread.Sleep(500);
}
}
}
}
In accordance to my 4th edit, deleted (Commented out) the sleep at the event handler. I was sleeping during the event handler, thus I couldn't receive anything that the microcontroller would send to me. Code works fine as expected now. Nothing was wrong with the serial ports on either components.