C# TcpClient updating (for an IRC client) - c#

I am bascially trying to make a barebones IRC client with C#, WinForms, and TcpClient that will display raw data from the irc server onto the the text area (textbox1). However I am struggling on the updating code (reading the stream from the server). Right now I have a timer that runs a function (listener) that reads from the TCP stream every 100ms. However my application freezes and the cursor disapeears, and the application hangs trying to grab more data. So what would be a better updating function?
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;
using System.Net.Sockets;
namespace LogernIRC
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Variables
TcpClient client;
StreamReader sr;
StreamWriter sw;
//Functions
public void connect(string host)
{
client = new TcpClient(host, 6667);
sr = new StreamReader(client.GetStream());
sw = new StreamWriter(client.GetStream());
}
public void write(string str)
{
textBox1.Text += str;
}
public void sendData(string str)
{
sw.WriteLine(str);
sw.Flush();
}
public void listener()
{
string data = sr.ReadLine();
write(data);
}
//End Functions
private void Form1_Load(object sender, EventArgs e)
{
//Initialize
write("Welcome to LogernIRC. Type \"/help\" for help with commands.\r\n");
}
private void button1_Click(object sender, EventArgs e) //Submit button clicked
{
//TextBox 1 is the text area , textbox 2 is the message/command area
//Command Area
if (textBox2.Text == "/help")
{
write("Help:\r\n/connect Connect to IRC server\r\n/help Display this help menu\r\n/join Join channel");
}
if (textBox2.Text.StartsWith("/connect"))
{
write("\r\nConnecting to " + textBox2.Text.Split(' ')[1] + " on port 6667...");
connect(textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text.StartsWith("/join"))
{
write("\r\nJoining channel " + textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text == "/test")
{
timer1.Start();
connect("irc.freenode.net");
write("\r\nActivating test function...");
sendData("NICK Logern");
sendData("USER Logern 0 * :LOGERN");
listener();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
//Read Data
listener();
}
}
}

The delay happens when your timer event is raised, but there's no data to read. It will just sit and wait until there is. The best way to address the issue is to use asynchronous operations to handle the I/O. For example:
public Form1()
{
InitializeComponent();
}
//Variables
TcpClient client;
StreamReader sr;
StreamWriter sw;
//Functions
public void connect(string host)
{
client = new TcpClient(host, 6667);
sr = new StreamReader(client.GetStream());
sw = new StreamWriter(client.GetStream());
}
public void write(string str)
{
textBox1.Text += str;
}
public void sendData(string str)
{
sw.WriteLine(str);
sw.Flush();
}
public async Task listener()
{
try
{
string data
while ((data = await sr.ReadLineAsync()) != null)
{
write(data);
}
}
catch (ObjectDisposedException)
{
// socket was closed forcefully
}
}
//End Functions
private void Form1_Load(object sender, EventArgs e)
{
//Initialize
write("Welcome to LogernIRC. Type \"/help\" for help with commands.\r\n");
}
private void button1_Click(object sender, EventArgs e) //Submit button clicked
{
//TextBox 1 is the text area , textbox 2 is the message/command area
//Command Area
if (textBox2.Text == "/help")
{
write("Help:\r\n/connect Connect to IRC server\r\n/help Display this help menu\r\n/join Join channel");
}
if (textBox2.Text.StartsWith("/connect"))
{
write("\r\nConnecting to " + textBox2.Text.Split(' ')[1] + " on port 6667...");
connect(textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text.StartsWith("/join"))
{
write("\r\nJoining channel " + textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text == "/test")
{
connect("irc.freenode.net");
// initiate async reading (storing the returned Task in a variable
// prevents the compiler from complaining that we don't await the
// call).
var _ = listener();
write("\r\nActivating test function...");
sendData("NICK Logern");
sendData("USER Logern 0 * :LOGERN");
}
}
The above example leaves out some error-checking and other niceties, but it's the basic idea of what you want to do.

It's not running async, right? So the UI will lock up until the loop is done. You're looping forever, right? That's pretty common with IRC bots/clients; I've done it myself.
If so, and if you're using NET 4.0 and above, you could try this:
await Task.Run(()=> { CodeThatLoopsForever(); });
Let me try to explain it better. Let's say for example you have a function like this:
private void Connect()
{
while (true)
{
// Do socket listening
}
}
And you call it from clicking a button, like this:
private void btn_Connect_Click(object sender, EventArgs e)
{
Connect();
}
You could just change that button code to this:
private async void btn_Connect_Click(object sender, EventArgs e)
{
await Task.Run(()=> { Connect(); });
}
Hope this helps!
UPDATE: .NET 4.0 and above!

Related

Waiting for a serial message before proceeding in C#

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();
}
}
}

Showing result of Ping.SendAsync in label text

I'm trying to create a simple GUI implementation of the ping program. I have a form which is just a text box textBox1 where users enter the IP as a string, press a button Ping, and the result of the ping is displayed in a label label1. For some reason the text wont show up when I run the program.
Code partially taken from Ping.SEndAsync:
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;
using System.Threading;
using System.Net.NetworkInformation;
using System.Net;
namespace pinger
{
public partial class Form1 : Form
{
private string address;
private string response;
private PingReply reply;
//public string response;
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
if (e.Cancelled)
((AutoResetEvent)e.UserState).Set();
if (e.Error != null)
((AutoResetEvent)e.UserState).Set();
reply = e.Reply;
((AutoResetEvent)e.UserState).Set();
if (reply == null)
return;
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
address = IPtextbox.Text;
}
private void Ping_click(object sender, EventArgs e)
{
AutoResetEvent waiter = new AutoResetEvent(false);
Ping pingSender = new Ping(); //creates a new 'pingSender' Ping object
pingSender.PingCompleted +=
new PingCompletedEventHandler(PingCompletedCallback);
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 1000;
pingSender.SendAsync(address, timeout, buffer, waiter);
}
private void label1_Click(object sender, EventArgs e)
{
label1.Text = "the ping was: " + reply.Status.ToString();
Show();
Refresh();
}
}
}
According to your code you label only changes it's text when you click on it. label1_Click event is raised.
PingCompleted event to get information about the completion status and data collected by a call to the SendAsync methods. In it you can change your label text with the result of the ping.
Add all the code inside label1_Click to PingCompletedCallback method as follows;
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
if (e.Cancelled || e.Error != null)
((AutoResetEvent)e.UserState).Set();
reply = e.Reply;
if (reply == null)
return;
//Change the label here
label1.Text = "the ping was: " + reply.Status.ToString();
Show();
Refresh();
}

C# Server-Client App(One Server-Multi Client)

I want to develop a client-server application. I started the project but I encountered the some problems. When I want to connect to server with one client, everything is done. Program is working. But when I want to connect with two or three etc. PC to server, clients of them is working but others is not working. How can I fix this problem?
Here is the 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.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Timers;
using ClientServer;
namespace ClientServer
{
public partial class Form1 : Form
{
private TcpClient Client;
private StreamReader STR;
public StreamWriter STW;
public string receive;
public string text_to_send;
//int zaman;
public Form1()
{
InitializeComponent();
- Client = new TcpClient();
Control.CheckForIllegalCrossThreadCalls = false; //cross threading problem
IPAddress[] LocalIP = Dns.GetHostAddresses(Dns.GetHostName()); // my IP Adress
foreach (IPAddress adress in LocalIP)
{
if(adress.AddressFamily== AddressFamily.InterNetwork)
{
textBox3.Text = adress.ToString();
}
}
}
private void button2_Click(object sender, EventArgs e) //Start server
{
TcpListener listener = new TcpListener(IPAddress.Any, int.Parse(textBox4.Text));
listener.Start();
Client = listener.AcceptTcpClient();
STR = new StreamReader(Client.GetStream());
STW = new StreamWriter(Client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); //receive data background
backgroundWorker2.WorkerSupportsCancellation = true; //ability cancel this thread
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) //receive data
{
while(Client.Connected)
{
try
{
receive = STR.ReadLine();
if(receive=="soru1")
{
label7.Text = "Merhaba bu bir denemedir :)";
//zaman = 45;
timer1.Enabled = true;
}
this.textBox2.Invoke(new MethodInvoker(delegate() { textBox2.AppendText("Sen:" + receive + "\n"); }));
receive = "";
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
}
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) //veri gönder
{
if(Client.Connected)
{
STW.WriteLine(text_to_send);
this.textBox2.Invoke(new MethodInvoker(delegate() { textBox2.AppendText("Ben:" + text_to_send + "\n"); }));
}
else
{
MessageBox.Show("Gönderim başarısız!");
}
backgroundWorker2.CancelAsync();
}
private void button3_Click(object sender, EventArgs e) //Connect Server
{
Client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse(textBox5.Text), int.Parse(textBox6.Text));
try
{
Client.Connect(IP_End);
if(Client.Connected)
{
textBox2.AppendText("Server'a bağlantı sağlandı" + "\n");
STW = new StreamWriter(Client.GetStream());
STR = new StreamReader(Client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); //receive data in background
backgroundWorker2.WorkerSupportsCancellation = true; //
}
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
private void button1_Click(object sender, EventArgs e) //Send Button
{
if(textBox1.Text != "")
{
text_to_send = textBox1.Text;
backgroundWorker2.RunWorkerAsync();
}
textBox1.Text = "";
}
//private void timer1_Tick(object sender, System.EventArgs e) //
//{
// zaman--; //timer her saniyede sayıyı 1 azaltacak
// label9.Text = zaman.ToString();
// if (zaman == 0)
// {
// timer1.Enabled = false;
// }
//}
}
}
Here a good links:
http://www.mikeadev.net/2012/07/multi-threaded-tcp-server-in-csharp/
https://www.codeproject.com/Articles/511814/Multi-client-per-one-server-socket-programming-in
tcpListener.Start();
Console.WriteLine("************This is Server program************");
Console.WriteLine("Hoe many clients are going to connect to this server?:");
int numberOfClientsYouNeedToConnect =int.Parse( Console.ReadLine());
for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}

How can i make my client-server app a multiclient-server app? C#

I have a little problem with setting my client-server app for multiple clients usage. I can connect to server and use one client. I modified a little the code to connect via second client, but i don't really know how can i read and send datas to server from second client that are visible also in first client and server. Any ideas/help? Thanks in advance!
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.Net.Sockets;
using System.IO;
using System.Threading;
namespace Server_WF
{
public partial class Form1 : Form
{
private TcpClient client;
static List<TcpListener> listeners = new List<TcpListener>();
public StreamReader SR;
public StreamWriter SW;
public string otrzymano;
public String msg;
public Form1()
{
InitializeComponent();
IPAddress[] localIP = Dns.GetHostAddresses(Dns.GetHostName()); // Pobieranie własnego IP
foreach(IPAddress adres in localIP)
{
if (adres.AddressFamily == AddressFamily.InterNetwork)
{
textBox3.Text = adres.ToString();
}
}
}
private void button2_Click(object sender, EventArgs e) // START SERVER
{
TcpListener listener = new TcpListener(IPAddress.Any, int.Parse(textBox4.Text));
listeners.Add(listener);
listener.Start();
client = listener.AcceptTcpClient();
SR = new StreamReader(client.GetStream());
SW = new StreamWriter(client.GetStream());
SW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); // Rozpocznij odbieranie danych
backgroundWorker2.WorkerSupportsCancellation = true; // Zdolność do usunięcia wątku
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // Odbieranie danych
{
while(client.Connected)
{
try
{
otrzymano = SR.ReadLine();
this.textBox2.Invoke(new MethodInvoker(delegate() { textBox2.AppendText("Ktoś: " + otrzymano + "\n"); }));
otrzymano = "";
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
}
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) // Przesyłanie danych
{
if(client.Connected)
{
SW.WriteLine(msg);
this.textBox2.Invoke(new MethodInvoker(delegate() { textBox2.AppendText("Ja: " + msg + "\n"); }));
}
else
{
MessageBox.Show("Wysyłanie nie powiodło się.");
}
backgroundWorker2.CancelAsync();
}
private void button3_Click(object sender, EventArgs e) // Połącz z serwerem
{
client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse(textBox5.Text), int.Parse(textBox6.Text));
try
{
client.Connect(IP_End);
if(client.Connected)
{
textBox2.AppendText("Połączono z serwerem..." + "\n");
SW = new StreamWriter(client.GetStream());
SR = new StreamReader(client.GetStream());
SW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); // Rozpocznij odbieranie danych
backgroundWorker2.WorkerSupportsCancellation = true; // Zdolność do usunięcia wątku
}
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
if(textBox1.Text != "")
{
msg = textBox1.Text;
backgroundWorker2.RunWorkerAsync();
}
textBox1.Text = "";
}
}
}
Oh dear, there's a lot to do in your code. First of all: don't call CancelAsync from your background worker code. It is not necessary and probably causes problem. Also, a background worker should never ever display MessageBoxes!
Secondly, a background worker is not the right tool in this case!
Thirdly: You need to make your code completely asynchronous. So please look into the BeginAcceptTcpClient. Then, handle each connected client in its own thread (NOT background worker!).
It's probably best you google for examples on how to do this, as this would be far too much to write up here.

Get Weight From Weigh Bridge Machine Using Serial Port in C#

i am develop application for getting weight from weigh Bridge machine using C#.Net.i am trying lot of ways but,doesn't read correct data format weight from weigh bridge machine.i am getting ouput like ?x???????x?x?x??x???x??x???x???x? continuously get from serial port.i want to get weight from weigh bridge machine my code is listed below:
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 SerialPortTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
String a = "";
private void button1_Click(object sender, EventArgs e)
{
serialPort1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
if (serialPort1.IsOpen == false)
{
serialPort1.Open();
}
timer1.Start();
button1.Enabled = false;
button2.Enabled = true;
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
a = a + serialPort1.ReadExisting();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (a.Length != 0)
{
textBox1.AppendText(a);
a = "";
}
}
private void button2_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen == true)
{
serialPort1.Close();
button2.Enabled = false;
button1.Enabled = true;
}
}
private void Form1_Load(object sender, EventArgs e)
{
if (serialPort1.IsOpen == true)
{
button1.Enabled = false;
button2.Enabled = true;
}
else
{
button1.Enabled = true;
button2.Enabled = false;
}
}
}
}
my code is append text from serial port data to textbox but,it's shows only like ?xxx?xxxx?xxxx?
can any one help me how to get weight from serial port using c#
Thanks For Reading My Post!
You are using ReadExisting(), that method tries to convert the bytes received by the port into a string. You'll get a question mark if that conversion fails. The default Encoding is ASCII, a byte value between 128 and 255 is not an ASCII character and thus produces a ?
Several possible reasons, roughly in order of likelihood:
Using the wrong baud rate, in particular guessing too high.
The device might be sending binary data, not strings. Which requires using Read() instead of ReadExisting and decoding the binary data.
Electrical noise picked up by a long cable that isn't shielded well enough. Easy to eliminate as a possible reason by disconnecting the cable at the bridge end. If that stops the data then it isn't likely to be noise.
Be sure to thoroughly read the manual. Contact the vendor of the device if you don't have one or can't make sense of it.
This code will be reading weightbridge continuously in background. Be sure to connect the pc with serial port. Also in design page Form1.cs[Design] you need to add Serial port from the toolbox. This code works for me, I hope it works for you too...
public partial class Form1 : Form
{
//Initialize the port and background Worker
private SerialPort port;
private BackgroundWorker backgroundWorker_Indicator;
public Form1()
{
backgroundWorker_Indicator = new BackgroundWorker();
backgroundWorker_Indicator.WorkerSupportsCancellation = true;
backgroundWorker_Indicator.DoWork += new DoWorkEventHandler(Indicator_DoWork);
//set the port according to your requirement.
port = new SerialPort("COMM2", 2400, Parity.None, 8, StopBits.One);
port.DataReceived += new SerialDataReceivedEventHandler(this.Indicator_DataReceived);
}
//button which starts the method. You can also put the method in Form1_Load()
private void SerialPortButton(object sender, EventArgs e)
{
StartStopIndicator();
}
private void StartStopIndicator()
{
try
{
port.Open();
backgroundWorker_Indicator.RunWorkerAsync();
}catch (Exception ea)
{
MessageBox.Show("13 "+ea.Message);
}
}
// Not a button. Just a methood.
private void Indicator_DoWork(object sender, DoWorkEventArgs e)
{
}
private void Indicator_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string str = StripNonNumeric(port.ReadLine());
UpdateWeightOnUI(str);
}
catch (Exception eb)
{
MessageBox.Show("12"+eb.Message);
}
}
private void UpdateWeightOnUI(string Weight)
{
try
{
// A label named weightLabel from the toolbox. This will keep updating on weight change automatically
if (weightLabel.InvokeRequired)
{
this.Invoke((Delegate)new Form1.SetTextCallBack(this.UpdateWeightOnUI), (object)Weight);
}
else
{
weightLabel.Text = Weight;
}
}
catch (Exception ec)
{
MessageBox.Show("11"+ec.Message);
}
}
// This method will remove all other things except the integers
private string StripNonNumeric(string original)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (char c in original)
{
if (char.IsDigit(c))
stringBuilder.Append(c);
}
return stringBuilder.ToString();
}
private delegate void SetTextCallBack(string text);

Categories