I'm currently working on an interface between C# and an arduino project. I'm using the serial port to send and receive messages from the arduino and so far everything looks fine.
However I came to a point, where I want to send a string to the arduino and wait for a response until I'm going to send over the next string.
I figured that I cannot simply timeout here since my RichTextField is also going to freeze and the "OK*" message cannot be read from there.
I've read about some other solutions online but since I'm very new to C# I hope that somebody can point me in the right direction.
Best regards
//Edited the post with a full code example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
namespace interface_test
{
public partial class Form1 : Form
{
string serialDataIn;
public Form1()
{
InitializeComponent();
Enable_Console();
comboBox_baudRate.Text = "115200";
comboBox_comPort.Text = "COM3";
string[] portLists = SerialPort.GetPortNames();
comboBox_comPort.Items.AddRange(portLists);
}
private void Form1_Load(object sender, EventArgs e)
{
}
/* erase textbox contents */
private void button_clearLog_Click(object sender, EventArgs e)
{
richTextBox_receiveMsg.Text = "";
}
/* listening to the serial port */
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
serialDataIn = serialPort1.ReadExisting();
this.Invoke(new EventHandler(ShowData));
}
/* process the serial data */
public void ShowData(object sender, EventArgs e)
{
string trimmedMsg = serialDataIn;
richTextBox_receiveMsg.Text += trimmedMsg;
if (trimmedMsg.Contains("Initialization done."))
{
button_detectCEM.Enabled = false;
}
}
/* open COM-port to arduino */
private void button_openCom_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = comboBox_comPort.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox_baudRate.Text);
serialPort1.Open();
Enable_Console();
button_detectCEM.Enabled = true;
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
/* close COM-port to arduino */
private void button_closeCom_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
try
{
serialPort1.Close();
Enable_Console();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
private void button_fileBrowser_Click(object sender, EventArgs e)
{
openAndWrite();
}
public void openAndWrite()
{
/* load a .txt file */
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = "c:\\";
openFileDialog1.Filter = "TXT files (*.txt)|*.txt";
openFileDialog1.FilterIndex = 0;
openFileDialog1.RestoreDirectory = true;
string selectedFile = "";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
selectedFile = openFileDialog1.FileName;
}
/* parse file and store it in data[] */
byte[] data;
using (FileStream fsSource = new FileStream(selectedFile, FileMode.Open, FileAccess.Read))
{
data = new byte[fsSource.Length];
int numBytesToRead = (int)fsSource.Length;
int numBytesRead = 0;
while (numBytesToRead > 0)
{
// Read may return anything from 0 to numBytesToRead.
int n = fsSource.Read(data, numBytesRead, numBytesToRead);
// Break when the end of the file is reached.
if (n == 0)
break;
numBytesRead += n;
numBytesToRead -= n;
}
numBytesToRead = data.Length;
}
for (int i = 0; i < BitConverter.ToInt32(blockLength, 0); i++)
{
data[i] = data[offset + i];
}
/* write data block */
offset = 0;
while (offset < data.Length)
{
byte[] dataString = new byte[6];
string blockMsg = "FFFFFF";
int start = offset;
offset += 6;
if (offset > data.Length) offset = data.Length;
for (int i = 0; i < 6; i++)
{
if ((start + i) < data.Length) dataString[i] = data[start + i];
}
blockMsg += BitConverter.ToString(dataString).Replace("-", string.Empty);
blockMsg += "*";
serialPort1.Write(blockMsg);
//Wait for "OK*" before next Message...
}
}
}
}
}
There's a few ways that you could solve this. My approach would be to make use of the TaskCompletionSource class and a lambda function. Here's a rough example, you'll need to make the method containing this code async, and potentially have it return a Task to await it all the way up the chain.
var tcs = new TaskCompletionSource<string>();
serialPort1.DataReceived += (s, e) =>
{
SerialPort sp = (SerialPort)s;
string newData = sp.ReadExisting();
tcs.SetResult(newData);
}
serialPort1.Write(Msg);
var dataFromPort = await tcs.Task;
I'm away from an IDE, nor do I have access to all your code, so without the wider context it's hard to know exactly what else you might need. But I've done some Arduino work in the past, and this is how I solved the problem.
EDIT :: Thinking about it, you might (test it first) run into a problem because that event isn't being unsubscribed from and the code is running in a loop. IF that turns out to be a problem, you could make use of C#'s Local Functions to handle the event subscription, like this:
var tcs = new TaskCompletionSource<string>();
void localHandler(object s, SerialDataReceivedEventArgs e)
{
serialPort1.DataReceived -= localHandler;
SerialPort sp = (SerialPort)s;
string newData = sp.ReadExisting();
tcs.SetResult(newData);
};
serialPort1.DataReceived += localHandler
serialPort1.Write(Msg);
var dataFromPort = await tcs.Task;
It might look a little strange, but it's certainly cleaner (IMO) then needing to keep track of instance variables and manually manage threads.
EDIT2 :: Tested when I was sat at a computer, if I understand your requirement correctly, this should do everything you need.
This may take you in the right direction.
It might be useful in this case to separate the data received from the display update thread. Since the data received is an event, it will be coming in on its own thread, likely from some component - in this case the serial port.
The form, and all the display objects on it, run on a single thread, owned by the form.
You can use a timer as a background thread to make the leap between what was received and what you want to do/display.
For example, one way is to use a concurrent queue and a timer to poll the status of the queue.
using System.Collections.Concurrent;
private ConcurrentQueue<string> dataIn = new ConcurrentQueue<string>();
private System.Threading.Timer timer = new System.Threading.Timer(CheckQue,null,TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(1));
private void CheckQue(object state)
{
while(dataIn.TryDequeue(out var data))
{
ShowData(data);
if (data.Contains("OK*"))
{
//Do Something
//Better yet raise an event that does something
Msg += BitConverter.ToString(dataString).Replace("-", string.Empty);
Msg += "*";
serialPort1.Write(Msg);
}
}
}
Then modify your above code to add to the queue when data is received
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
dataIn.Enqueue(SerialPort1.ReadExisting());
}
And since your using a windows form, you need to make sure you don't get a cross-threaded operation when updating it, by marshaling the update onto the form's thread like so.
public static void ShowData(string data)
{
if (this.InvokeRequired)
{
var del = new MethodInvoker(() => ShowData(data));
try
{
this.Invoke(del);
return;
}
catch
{ }
}
richTextBox_receiveMsg.Text += data;
}
EDIT based on your revised question:
To modify for sending blocks of a file you could added another Que
private ConcurrentQueue<string> dataOut = new ConcurrentQueue<string>();
Then when you read the file, do whatever processing you need and put the final output in the queue and finish by sending the first block.
public void openAndWrite()
{
/* load a .txt file */
.
.
.
while (offset < data.Length)
{
.
.
blockMsg += BitConverter.ToString(dataString).Replace("-", string.Empty);
blockMsg += "*";
dataOut.Enqueue(blockMsg);
}
SendBlock();
}
Where SendBlock looks like this
private void SendBlock()
{
if(dataOut.TryDequeue(out var data))
{
serialPort1.Write(data);
}
}
Then just modify the timer handler to send blocks as needed
private void CheckQue(object state)
{
while (dataIn.TryDequeue(out var data))
{
ShowData(data);
if (data.Contains("OK*"))
{
SendBlock();
}
}
}
Related
so im new in C# Programming. I have programmed a C# Forms Application in Visual Studio to communicate to/initialze a device over the Serial Port. The communication between the device is COBS coded, so there are no 0x00 bytes except on the end of each message. The messages sent and received have different length.
My problem is at the moment, that the Messages I receive are not complete or start at the middle of a message, so i cannot trigger sent messages on a specific value in the received messages. You can determine end of a message with received 0x00 (0x00 means end of message in COBS coded data)
So what i need is something to handle the complete message and put it in a byte array to analyze i.e. byte[11] for a specific value.
Here is what ive done so far:
private bool b_portopen = false;
private byte[] b_rcv_buffer = new byte[256];
private void button1_Click(object sender, EventArgs e) {
//InitTimer();
if (b_portopen == false)
{
serialPort1.PortName = comboBox1.SelectedItem.ToString();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
serialPort1.Open();
b_portopen = true;
button1.Text = "Close";
button2.Enabled = true;
Console.WriteLine("Serial Port Opened");
}
else if (b_portopen == true)
{
serialPort1.Close();
b_portopen = false;
button1.Text = "Open";
button2.Enabled = false;
Console.WriteLine("Serial Port Closed");
}
}
private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
serialPort1.Read(b_rcv_buffer, 0, 256);
//serialPort1.Read(b_rcv_buffer1, 11, 2);
richTextBox1_receive.Invoke(new Action(() =>
{
richTextBox1_receive.AppendText(BitConverter.ToString(b_rcv_buffer) + "\n");
richTextBox1_receive.ScrollToCaret();
}));
switch (b_rcv_buffer[10])
{
case b_state_startup:
do something
case b_state_be_start_conf:
do something
case b_state_keepalive_conf:
do something
case b_state_unprepare_conf:
do something
case b_state_prepare_conf:
do something
}
}
So, i found a solution with using ConcurrentQueue:
ConcurrentQueue<byte> b_rcv_buffer = new ConcurrentQueue<byte>();
private Timer timer2;
public void InitTimer()
{
timer2 = new System.Windows.Forms.Timer();
timer2.Tick += new EventHandler(timer2_Tick);
timer2.Interval = 1; // in miliseconds
timer2.Start();
}
private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int bytes = serialPort1.BytesToRead;
byte[] buf = new byte[bytes];
serialPort1.Read(buf, 0, serialPort1.BytesToRead);
for(int i = 0; i < buf.Length; i++)
{
b_rcv_buffer.Enqueue(buf[i]); //Enqueue every received Byte in Concurrentqueue
}
}
private async void timer2_Tick(object sender, EventArgs e)
{
if (b_rcv_buffer.Contains<byte>(0x00))
{
byte[] array = b_rcv_buffer.ToArray();
richTextBox1_receive.Invoke(new Action(() =>
{
richTextBox1_receive.AppendText(BitConverter.ToString(array) + "\n");
//richTextBox1_receive.ScrollToCaret();
}));
byte ignored;
while (b_rcv_buffer.TryDequeue(out ignored));
}
I am using Fiddler API. In this API I am using AfterSessionComplete event. This event fires whenever I am accessing any page on the browser. This event also calls the method i.e. (drawGraph_2(List<Fiddler.Session>)). The method has the functionality of drawing the graph. I am sharing the code with you. For few requests I am able to draw the graph but once I access too many pages I get this error i.e collection is modified.
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using Fiddler;
using System.Threading;
namespace MSRealTime
{
public partial class Form1 : Form
{
static int i = 0;
List<Fiddler.Session> fs = new List<Session>();
int iSecureEndpointPort = 8877, get = 0, post = 0, threshold_value = 0;
string sSecureEndpointHostname = "localhost";
Proxy oSecureEndpoint;
static int k = 0;
TimeSpan cbr, sbr, cdr;
double rt, request_response_time;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
List<Fiddler.Session> numb = new List<Session>();
//List<Fiddler.Session> removeprev = new List<Fiddler.Session>();
#region AttachEventListeners
Fiddler.FiddlerApplication.BeforeRequest += delegate (Fiddler.Session oS)
{
oS.bBufferResponse = false;
Monitor.Enter(numb);
numb.Add(oS);
Monitor.Exit(numb);
oS["X-AutoAuth"] = "(default)";
};
//this event fires when server response received by fiddler
Fiddler.FiddlerApplication.BeforeResponse += delegate (Fiddler.Session oS)
{
string s = oS.PathAndQuery;
int i = oS.port;
};
//this event fires when a session has been completed
Fiddler.FiddlerApplication.AfterSessionComplete += delegate (Fiddler.Session oS)
{
//URLMonInterop.SetProxyInProcess("127.0.0.1:8888", "<-loopback>");
CheckForIllegalCrossThreadCalls = false;
if (oS.HTTPMethodIs("CONNECT")) { return; }
else
{
label1.Text = numb.Count.ToString();
}
//Monitor.Enter(numb);
numb.Add(oS);
//removeprev.Add(oS);
numb = numb.OrderBy(x => x.id).ToList();
// Monitor.Exit(numb);
//numb.Add(TimeSpan.Parse(oS.Timers.ClientBeginRequest.ToString()).TotalMilliseconds-TimeSpan.Parse(oS.Timers.ClientBeginRequest.ToString()).TotalMilliseconds);
drawGraph_2(numb);
//numb.Clear();
};
#endregion AttachEventListeners
//Fiddler.CONFIG.IgnoreServerCertErrors = true;
FiddlerCoreStartupFlags oFCSF = FiddlerCoreStartupFlags.Default;
try
{
Fiddler.FiddlerApplication.Startup(iSecureEndpointPort, oFCSF);
}
catch (Exception exe) { MessageBox.Show(exe.Message); }
FiddlerApplication.Log.LogFormat("Created endpoint listening on port {0}", iSecureEndpointPort);
FiddlerApplication.Log.LogFormat("Starting with settings: [{0}]", oFCSF);
FiddlerApplication.Log.LogFormat("Gateway: {0}", CONFIG.UpstreamGateway.ToString());
oSecureEndpoint = FiddlerApplication.CreateProxyEndpoint(iSecureEndpointPort, true, sSecureEndpointHostname);
}
private void drawGraph_2(List<Fiddler.Session> numb)
{
//for (; i < numb.Count; i++)
//{
// fs[i] = numb[i];
//}
fs = numb;
//foreach (Session fs in numb)
for(;i<fs.Count;i++)
{
cbr = fs[i].Timers.ClientBeginRequest.TimeOfDay;
sbr = fs[i].Timers.ServerBeginResponse.TimeOfDay;
cdr = fs[i].Timers.ClientDoneResponse.TimeOfDay;
double cbr_millisecond = TimeSpan.Parse(cbr.ToString()).TotalMilliseconds;
double sbr_millisecond = TimeSpan.Parse(sbr.ToString()).TotalMilliseconds;
double cdr_millisecond = TimeSpan.Parse(cdr.ToString()).TotalMilliseconds;
rt = (cdr_millisecond - cbr_millisecond); // page response time
request_response_time = (sbr_millisecond - cbr_millisecond); // request response time
// Add point.
chart1.Series["Series1"].Points.AddXY(fs[i].id, rt);
}
}
}
Your event AfterSessionCompletefires faster than your handler code can process it. So your collection gets modified while you are still iterating it.
You will need to make a copy to have a collection that does not get modified.
You could do this by calling ToList on it as suggested:
fs = numb.ToList();
As you seem to handle it like an array afterwards anyway, you could also create an array straight away:
fs = numb.ToArray();
I've created an application that patches my game servers files.
However, I've got 3 problems which I can't solve:
When downloading a new patch, it doesn't update the progressbar instantly, but refreshes it after around 30-40 seconds
I want a label to show how much mega bytes they are downloading, and how much they have so far (for example: 122Mb/750Mb
When downloading, I want a label to show ~% of how much it has downloaded so far
I am not sure how to add number 2 and 3, and the number 1 problem just seems ridiculous, because there's nothing that indicates it should refresh after 30-40 seconds in my coding (at least as far as I know)
My backgroundWorker1_DoWork:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Defines the server's update directory
string Server = "http://localhost/dl/game-updates/";
//Defines application root
string Root = AppDomain.CurrentDomain.BaseDirectory;
//Make sure version file exists
FileStream fs = null;
if (!File.Exists("version"))
{
using (fs = File.Create("version"))
{
}
using (StreamWriter sw = new StreamWriter("version"))
{
sw.Write("1.0");
}
}
//checks client version
string lclVersion;
using (StreamReader reader = new StreamReader("version"))
{
lclVersion = reader.ReadLine();
}
decimal localVersion = decimal.Parse(lclVersion);
//server's list of updates
XDocument serverXml = XDocument.Load(#Server + "Updates.xml");
//The Update Process
foreach (XElement update in serverXml.Descendants("update"))
{
string version = update.Element("version").Value;
string file = update.Element("file").Value;
decimal serverVersion = decimal.Parse(version);
string sUrlToReadFileFrom = Server + file;
string sFilePathToWriteFileTo = Root + file;
if (serverVersion > localVersion)
{
Uri url = new Uri(sUrlToReadFileFrom);
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
response.Close();
Int64 iSize = response.ContentLength;
Int64 iRunningByteTotal = 0;
using (System.Net.WebClient client = new System.Net.WebClient())
{
using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
{
using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
int iByteSize = 0;
byte[] byteBuffer = new byte[iSize];
while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
streamLocal.Write(byteBuffer, 0, iByteSize);
iRunningByteTotal += iByteSize;
double dIndex = (double)(iRunningByteTotal);
double dTotal = (double)byteBuffer.Length;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
backgroundWorker1.ReportProgress(iProgressPercentage);
}
streamLocal.Close();
}
streamRemote.Close();
}
}
//unzip
using (ZipFile zip = ZipFile.Read(file))
{
foreach (ZipEntry zipFiles in zip)
{
zipFiles.Extract(Root + "\\", true);
}
}
//download new version file
WebClient webClient = new WebClient();
webClient.DownloadFile(Server + "version.txt", #Root + "version");
//Delete Zip File
deleteFile(file);
}
}
}
My backgroundWorker1_ProgressChanged:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label1.Text = "Downloading updates...";
}
And my backgroundWorker1_RunWorkerCompleted:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
settings_btn.Enabled = true;
start_btn_disabled.Enabled = false;
start_btn_disabled.Visible = false;
start_btn.Visible = true;
start_btn.Enabled = true;
progressBar1.Value = 100;
label1.Text = "Client is up to date!";
}
Also, a side note: I'm also having a bit problems of updating labels in backgroundWorker2_DoWork?
Any ideas?
Here's some working code which updates a label on Form1 using the BackgroundWorker.
Create a new Windows Form project and drop it in your code and it'll work.
It's super ugly, but it works.
After that, just plug your code into the DoWork method and calculate your value and send to ReportProgress.
Keep in mind that the work done in DoWork method is the actual Background Thread.
That means that in that method (DoWork) you cannot access UI (form) elements because they are on the UI thread.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Enabled = true;
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
FakeCountingWork();
}
private void FakeCountingWork()
{
int totalNumber = 100;
int progressCounter = 0;
while (progressCounter < totalNumber)
{
int fakecounter = 0;
for (int x = 0; x < 100000000; x++)
{
fakecounter++;
}
progressCounter++;
backgroundWorker1.ReportProgress(progressCounter);
}
}
}
################################## EDITED TO ADD OTHER FUNCTIONALITY
Okay, here's how you can implement a label which displays the number of bytes downloaded so far.
Add a second label named label2 to your form.
Next alter the following methods from my previous example.
Here we are going to use the UserState to pass an extra value to the ProgressChanged Event. It's very simple. You can see that I'm generating a random number and it will now appear in Label2. This is where you could show your number of bytes.
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
label2.Text = e.UserState.ToString();
}
private void FakeCountingWork()
{
int totalNumber = 100;
int progressCounter = 0;
Random rnd = new Random();
while (progressCounter < totalNumber)
{
int fakecounter = 0;
for (int x = 0; x < 100000000; x++)
{
fakecounter++;
}
progressCounter++;
updateValue = rnd.Next();
backgroundWorker1.ReportProgress(progressCounter,updateValue);
}
}
I would imagine this is because you are trying to update UI objects on a different thread. HAve you tried using the Dispatcher if using wpf? https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke(v=vs.110).aspx
or Invoke if using Winforms? https://msdn.microsoft.com/fr-ca/library/zyzhdc6b(v=vs.85).aspx
Edit:
As #daylight pointed out to be, the UI was being updated in the progresschanged event, which executes on the thread which created the background worker, therefore there shouldn't be an issue regarding threading. See https://msdn.microsoft.com/en-us/library/ka89zff4(v=vs.110).aspx for more info
I have a problem regarding the rs232 communication with a Melfa rv-2aj robot. I am sending to commands in ASCII and when the robot replies via rs232 I get something like this: ??QY?e0?L???0???0???. My first thought was that I am not doing a proper conversion from ASCII when I read from RS232, but if I convert this set of charaters to a unicode output I get some chinesse characters and this should not be right. As the robot sends a reply via rs232, makes me think that my implementation is not wrong , but maybe my approch has some faults in it. I think "?" represent ASCII characters that are not properly displayed.
Below I have attached the source code to my application.
Can somebody give some pointers on what I doing wrong when I am reading from the serial that i get his kind of ouput?
I would really appreciate any kind of help, suggestion or reference.
Thank you very much.
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;
namespace RS232_Communication
{
public partial class Form1 : Form
{
private SerialPort COM_port = new SerialPort();
private byte[] _array = new byte[] {0};
public Form1()
{
InitializeComponent();
BAUDRate.Items.Add("2400");
BAUDRate.Items.Add("4800");
BAUDRate.Items.Add("9600");
BAUDRate.Items.Add("14400");
BAUDRate.Items.Add("19200");
BAUDRate.Items.Add("28800");
BAUDRate.SelectedIndex = 2;
DATAUnit.Items.Add("5");
DATAUnit.Items.Add("6");
DATAUnit.Items.Add("7");
DATAUnit.Items.Add("8");
DATAUnit.Items.Add("9");
DATAUnit.SelectedIndex = 3;
ParityUnit.Items.Add("None");
ParityUnit.Items.Add("Odd");
ParityUnit.Items.Add("Even");
ParityUnit.Items.Add("Mark");
ParityUnit.Items.Add("Space");
ParityUnit.SelectedIndex = 2;
STOPUnit.Items.Add("One");
STOPUnit.Items.Add("Two");
STOPUnit.SelectedIndex = 1;
this.Load += new EventHandler(Form1_Load);
SendText.KeyPress +=new KeyPressEventHandler(SendText_KeyPress);
COM_port.DataReceived +=new SerialDataReceivedEventHandler(COM_port_DataReceived);
}
private string GetString(byte[] bBuffer, int iIndex, int iLen, bool bUni)
{
string sBuffer;
if (bUni) sBuffer = Encoding.Unicode.GetString(bBuffer, iIndex, iLen);
else sBuffer = Encoding.ASCII.GetString(bBuffer, iIndex, iLen);
//return the string
return sBuffer;
}
void COM_port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
ReceiveText.Invoke(new EventHandler(delegate
{
byte[] data = new Byte[COM_port.BytesToRead];
COM_port.Read(data, 0, data.Length);
//string read = GetString(data, 0, data.Length, true);
string read = System.Text.Encoding.ASCII.GetString(data);
ReceiveText.AppendText(read);
//ReceiveText.AppendText(COM_port.ReadExisting());
}
)
)
;
}
void Form1_Load(Object sender, EventArgs e)
{
foreach (string COMstr in SerialPort.GetPortNames())
COMPort.Items.Add(COMstr);
if (COMPort.Items.Count > 0)
COMPort.SelectedIndex = 0;
else MessageBox.Show("No COM Ports available");
}
private void ConnectBTN_Click(object sender, EventArgs e)
{
try
{
if (COM_port.IsOpen)
{
COMPort.Enabled = true;
BAUDRate.Enabled = true;
ParityUnit.Enabled = true;
STOPUnit.Enabled = true;
DATAUnit.Enabled = true;
COM_port.DtrEnable = false;
COM_port.RtsEnable = false;
ConnectBTN.Text = "Connect";
COM_port.Close();
}
else
{
COM_port.BaudRate = int.Parse(BAUDRate.Text);
COM_port.Parity = (Parity)Enum.Parse(typeof(Parity), ParityUnit.Text);
COM_port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), STOPUnit.Text);
COM_port.DataBits = int.Parse(DATAUnit.Text);
COM_port.PortName = COMPort.Text;
//COM_port.DtrEnable = true;
//COM_port.RtsEnable = true;
COM_port.Open();
COM_port.ReadTimeout = 2000;
COM_port.WriteTimeout = 2000;
COMPort.Enabled = false;
BAUDRate.Enabled = false;
ParityUnit.Enabled = false;
STOPUnit.Enabled = false;
DATAUnit.Enabled = false;
ConnectBTN.Text = "Disconnect";
}
}
catch
{
MessageBox.Show("Connection Error");
}
}
public void WriteBytes(byte[] array)
{
COM_port.Write(array, 0, array.Length);
}
public void WriteBytes(byte[] array, int index, int length)
{
COM_port.Write(array, index, length);
}
public void WriteLine(String line)
{
//string s="";
//foreach (byte b in StringToBytes(line + "\r\n"))
// s = s + b.ToString();
//COM_port.WriteLine(s);
WriteBytes(StringToBytes(line + "\r\n"));//CR + LF
}
public static byte[] StringToBytes(string input)
{
return Encoding.ASCII.GetBytes(input);
}
private void SendBTN_Click(object sender, EventArgs e)
{
if (SendText.Text != "")
{
WriteLine(SendText.Text);
//COM_port.WriteLine(SendText.Text);
SendText.Text = "";
}
}
void SendText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
WriteLine(SendText.Text);
//COM_port.WriteLine(SendText.Text);
SendText.Text = "";
}
}
}
}
I managed to figure out what was the problem. In the manual for the rv-2aj it is specified that in order to use the rs232 communication the following parameters have to be set: baud rate 9600, parity even, stop bits 2, data bits 8. So I configured my communication this way, and when I sent data to the controller I would receive strange messages as I showed in my previous post. It seems that the configuration for communication on the robot side was different then mine, so I changed the value for parity to none and the stop bits to one and now everything works as expected. I get proper feedback from the robot and the commands work. The code I wrote in c# works fine, no necessary modifications required.
This question already has answers here:
True Parallel Downloads
(2 answers)
Closed 8 years ago.
I am trying to download one file at a time. But when I add my value2 into the await Task.Delay(value2); It still downloads both files at the same instead of one at a time. Mind you that I will be putting checkboxes to the ones that I want to download and there are going to be about 20 to 50 downloads to which I would be able to choose which to download. But the main thing is how to download one at a time instead of all at the same 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.Net;
using System.Diagnostics;
namespace DownloadFileCSharp8
{
public partial class Form1 : Form
{
private Stopwatch workerTimeElaspsed;
public Form1()
{
InitializeComponent();
}
private async void btnGetDownload_Click(object sender, EventArgs e)
{
string text = label5.Text;
int value2;
//value2 = value2 + 5;
int.TryParse(text, out value2);
InitiateDownload("http://stie.text1.txt", #"E:\Files\text1.txt", wc_DownloadFileCompleted, "text1.txt");
await Task.Delay(value2);
InitiateDownload("http://site.text.docx", #"E:\Files\text2.docx", wc_DownloadFileCompleted, "text2.docx");
}
void InitiateDownload(string RemoteAddress, string LocalFile, AsyncCompletedEventHandler CompleteCallBack, object userToken)
{
WebClient wc = new WebClient();
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadTimer);
wc.DownloadFileCompleted += wc_DownloadFileCompleted;
wc.DownloadFileAsync(new Uri(RemoteAddress), LocalFile, userToken);
workerTimeElaspsed = new Stopwatch();
workerTimeElaspsed.Start();
}
private void DownloadTimer(object sender, DownloadProgressChangedEventArgs e)
{
progressBar2.Value = e.ProgressPercentage;
if (e.ProgressPercentage > 0)
{
double totalTime = (100d / (double)e.ProgressPercentage) * workerTimeElaspsed.Elapsed.TotalSeconds;
double remaining = totalTime - workerTimeElaspsed.Elapsed.TotalSeconds;
label5.Text = Math.Round(remaining).ToString();
}
}
void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
lblInfo1.Visible = true;
lblInfo1.ForeColor = Color.Red;
lblInfo1.Text = "Error Downloading ";
//throw e.Error;
}
else if (e.Cancelled)
{
lblInfo1.Visible = true;
lblInfo1.ForeColor = Color.Red;
lblInfo1.Text = "Download Cancelled " + e.UserState + e.Error;
}
else
{
lblInfo1.Visible = true;
lblInfo1.ForeColor = Color.Red;
lblInfo1.Text = e.UserState + " Download Complete!! ";
}
//throw new NotImplementedException();
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void progressBar1_Click(object sender, EventArgs e)
{
}
}
}
You call InitiateDownload to start the download, then wait for a fixed period of time (which appears to be very short), then you call InitiateDownload again to start another download *regardless of whether or not the first download has finished.
What you want to do is re-write InitiateDownload so that it returns a Task that indicates when the download is complete. You can then await that task and start the next download when it is done.
The easiest way to do that is to simply use the DownloadDataTaskAsync method instead of DownloadFileAsync.
You need to use your DownloadFileCompleted event to trigger the next InitiateDownload if you want them to happen serially.