I have made a simple windows form with a ComboBox, TextBox and two Buttons to setup a serial protocol with my hardware.
However, whenever I send something I do get reply from hardware but C# doesn't display it. Instead it gives an exception saying that the operation has timed out. I even used an oscilloscope to check if I received something and it was positive. But C# doesn't display the code as stated before.
I am attaching my code below. Anyhelp would be welcome. Thanks in advance.
public partial class Form3 : Form
{
string buffer;
public SerialPort myComPort = new SerialPort();
delegate void setTextCallback(string text);
public Form3()
{
InitializeComponent();
}
private void Form3_Load(object sender, EventArgs e)
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity");
foreach (ManagementObject queryObj in searcher.Get())
{
if (queryObj["Caption"].ToString().Contains("(COM"))
{
comboBox1.Items.Add(queryObj["Caption"]);
}
}
comboBox1.Text = comboBox1.Items[0].ToString();
}
catch (ManagementException ex)
{
MessageBox.Show(ex.Message);
}
}
private void setText(string text)
{
if (textBox1.InvokeRequired)
{
setTextCallback tcb = new setTextCallback(setText);
this.Invoke(tcb, new object[] { text });
}
else
{
textBox1.Text = text;
}
}
void myComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string myString = myComPort.ReadLine();
setText(myString);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void button1_Click(object sender, EventArgs e)
{
myComPort.Close();
// button1.Enabled = false;
string name = comboBox1.Text;
string[] words = name.Split('(', ')');
myComPort.PortName = words[1];
myComPort.ReadTimeout = 5000;
// myComPort.WriteTimeout = 500;
myComPort.BaudRate = 9600;
myComPort.DataBits = 8;
myComPort.StopBits = StopBits.One;
myComPort.Parity = Parity.None;
myComPort.DataReceived += new SerialDataReceivedEventHandler(myComPort_DataReceived);
myComPort.Open();
}
private void button2_Click(object sender, EventArgs e)
{
myComPort.WriteLine("?GV1\r");
}
}
It say
...The DataReceived event is not guaranteed to be raised for every byte received...
Try something like:
private static void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// prevent error with closed port to appears
if (!_port.IsOpen)
return;
// read data
if (_port.BytesToRead >= 1)
{
// ...
// read data into a buffer _port.ReadByte()
DataReceived(sender, e);
}
// ...
// if buffer contains data, process them
}
Have a look at this url:
http://csharp.simpleserial.com/
And this url for WMI:
http://www.codeproject.com/Articles/32330/A-Useful-WMI-Tool-How-To-Find-USB-to-Serial-Adapto
Related
I am creating a Windows Form application, where it is connecting to a device through bluetooth. I am able to send commands to the device and I am receiving the data continuously. The problem I am facing is that I am not able to show the continuous data in the text box. The text box only shows the first line of characters the application is receiving. Here is my code:
CONNECT BUTTON ACTION:
private void btnConnect_Click(object sender, EventArgs e)
{
if (listBox.SelectedItem != null)
{
lblProgress.Text = "";
btnStart.Enabled = true;
cBoxAvailablePorts.Enabled = cBoxAvailableBaudRates.Enabled = true;
try
{
int pos = listBox.SelectedIndex;
deviceInfo = array.ElementAt(pos);
if (pairDevice())
{
Thread thread = new Thread(() => connectThread());
thread.Start();
}
else
{
MessageBox.Show("Pair failed!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
else
{
MessageBox.Show("Please connect to a device!");
}
}
THREAD ACTION
private void connectThread()
{
//BluetoothClient client = new BluetoothClient();
bc.BeginConnect(deviceInfo.DeviceAddress, serviceClass, this.connectCallBack, bc);
}
CALLBACK ACTION:
private void connectCallBack(IAsyncResult result)
{
//BluetoothClient client = (BluetoothClient)result.AsyncState;
try
{
if (bc.Connected)
{
MessageBox.Show("Connected!");
}
else
{
MessageBox.Show("Connection Failed!");
}
}
catch (Exception)
{
MessageBox.Show("Not able to identify Bluetooth devices! Please try again.!");
}
}
START BUTTON ACTION:
Here I send a command "S".
In button action I call sendMessage("S").
The function that is called is shown below:
public void sendMessage(string msg)
{
try
{
if (bc.Connected)
{
Stream stream = bc.GetStream();
stream.ReadTimeout = 1000;
StreamWriter streamWriter = new StreamWriter(stream);
streamWriter.WriteLine(msg);
streamWriter.Flush();
// Read operation
StreamReader streamReader = new StreamReader(stream);
string result = streamReader.ReadLine();
txtResult.Text = result;
}
else
{
MessageBox.Show("Sending failed!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I wrote the StreamReader part in a loop, and it gave me Socket Exception.
I also tried to get the data from Serial Port and used DataReceived event just in case, but still it didn't help.
Any help would be appreciated.
Thank you!
OKAY! I solved the problem. Without getting in trouble with 32feet library (though it is fun to code with 32feet), I thought to make communication through serial port. I connected the device with my laptop and got to know the outgoing COMPORT in bluetooth setting of my laptop. The two-way communication can only be done through outgoing COMPORT, not the incoming COMPORT.
Suppose the outgoing COMPORT is COM12 and the baud rate that I have set is 9600.
So here is my code:
public delegate void updateDelegate(string text);
private updateDelegate objDelegate;
private SerialPort serialPort;
public View() // constructor
{
InitializeComponent();
this.WindowState = FormWindowState.Normal;
this.StartPosition = FormStartPosition.CenterScreen;
this.objDelegate = new updateDelegate(getText);
serialPort = new SerialPort("COM12", 9600);
serialPort.Handshake = Handshake.None;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
}
START BUTTON ACTION
private void btnStart_Click(object sender, EventArgs e)
{
sendData("S");
}
// SEND COMMAND
public void sendData(string msg)
{
try
{
if (!serialPort.IsOpen)
{
serialPort.Open();
//serialPort.Close();
}
if (serialPort.IsOpen)
{
serialPort.Write(msg);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// READ DATA
public void readData()
{
try
{
serialPort.DataReceived += SerialPort_DataReceived;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string res = serialPort.ReadExisting();
Thread.Sleep(500);
txtResult.Invoke(this.objDelegate, new object[] {res});
}
public void getText(string text)
{
txtResult.Text = text;
}
I hope this will help someone! Thank you!!!
I'm trying to plot the data read from a serial port using zedgraph. I'm still learing to code so I couldn't deduce why the plot does not work. Please have a look at the code and advice;
namespace WindowsApplication2
{
public partial class Form1 : Form
{
string t;
SerialPort sp;
Thread m_thread;
bool m_running = false;
ManualResetEvent m_event = new ManualResetEvent(true);
bool m_pause = false;
private GraphPane myPane;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
// User can already search for ports when the constructor of the FORM1 is calling
// And let the user search ports again with a click
// Searching for ports function
SearchPorts();
CreateZedGraph(); //error : Severity Code Description Project File Line Suppression State
//Error CS7036 There is no argument given that corresponds to the required formal parameter
//'w' of 'Form1.DrawPoint(ZedGraphControl, int, PointPair)'
}
// start button
private void btnStart_Click(object sender, EventArgs e)
{
if (m_thread == null || m_thread.IsAlive == false)
{
ClearGraph();
m_thread = new Thread(Process);
m_thread.Start();
}
}
void Process()
{
PointPair point = new PointPair();
btnStart.Enabled = false;
btnStop.Enabled = true;
m_running = true;
while (m_running == true)
{
m_event.WaitOne();
point.Y = Convert.ToDouble(serialPort1);
point.X++; //time instance of measurement??
DrawPoint(zed1, point);
ssData.Value = point.Y.ToString();
RefresheZedGraphs(zed1);
Thread.Sleep(700);
}
btnStart.Enabled = true;
}
private void CreateZedGraph(object sender, SerialDataReceivedEventArgs e, ZedGraphControl zgc)
{
myPane = zgc.GraphPane;
// axes stuff
myPane.Title.Text = "FRDM-KW40z serial Test";
myPane.XAxis.Title.Text = "Time";
myPane.YAxis.Title.Text = "Voltage";
myPane.XAxis.MajorGrid.IsVisible = true;
myPane.YAxis.MajorGrid.IsVisible = true;
myPane.XAxis.MinorGrid.IsVisible = true;
myPane.YAxis.MinorGrid.IsVisible = true;
// data from serial port
PointPairList list = new PointPairList();
zed1.GraphPane.AddCurve("Test", list, Color.Red);
}
To open and read from a serial port, I use a combox and a couple of buttons (and then later I try to save it to a text file);
private void button2_Click(object sender, EventArgs e)
{
comboBox1.Items.Clear();
SearchPorts();
}
void SearchPorts()
{
string[] ports = SerialPort.GetPortNames();
foreach (string port in ports)
{
comboBox1.Items.Add(port);
}
}
private void button3_Click(object sender, EventArgs e)
{
// Catch exception if it will be thrown so the user will see it in a message box
OpenCloseSerial();
}
void OpenCloseSerial()
{
try
{
if (sp == null || sp.IsOpen == false)
{
t = comboBox1.Text.ToString();
sErial(t);
button3.Text = "Close Serial port"; // button text
}
else
{
sp.Close();
button3.Text = "Connect and wait for inputs"; // button text
}
}
catch (Exception err) // catching error message
{
MessageBox.Show(err.Message); // displaying error message
}
}
void sErial(string Port_name)
{
try
{
sp = new SerialPort(Port_name, 115200, Parity.None, 8, StopBits.One); // serial port parameters
sp.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
sp.Open();
}
catch (Exception err)
{
throw (new SystemException(err.Message));
}
}
private void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
{
// This below line is not need , sp is global (belongs to the class!!)
//SerialPort sp = (SerialPort)sender;
if (e.EventType == SerialData.Chars)
{
if (sp.IsOpen)
{
string w = sp.ReadExisting();
if (w != String.Empty)
{
Invoke(new Action(() => Control.Update(w)));
}
}
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (sp == null || sp.IsOpen == false)
{
OpenCloseSerial();
}
}
The plot does not update! I can't quite guess why. Please tell me if there's mistakes in my approach or the code.
I get an error at : Invoke(new Action(() => Control.Update(w))); when trying to update the graph so that I can save after that.
I again have an error at: DrawPoint(zed1, point);
Thank you all for your time. Good day.
Cheers,
Ram.
To update the chart, you need to call the Invalidate method.
When you receive data from serial port, you need to convert it to double[] and add those points to your PointPairList.
PointPairList list = new PointPairList();
zed1.GraphPane.AddCurve("Test", list, Color.Red);
//Convert the received data to double array
double[] serialPortData = ....
//You may want to clear list first, by list.Clear();
list.Add(serialPortData);
//Invalidate the ZedGraphControl to update
zed1.Invalidate();
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.
I am getting error
System.TimeoutException was unhandled The operation has timed out... etc
while I am trying to read a barcode I tried a lot to solve it with but nothing worked out.
I checked parameters of SerialPort that matching Windows Device Manager many times.
I tried to replace
String data = _serialPort.ReadLine();
with
String data = _serialPort.ReadByte().ToString();
as you can see, but that show me unknown number it shows for example 12 then removed then 26 etc.
I tried to change the Encoding but when I change the encoding I am getting unknown characters, like empty squares black triangle or Playing card symbol etc.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
static SerialPort _serialPort;
private delegate void SetTextDeleg(string text);
private void Form1_Load(Object sender, EventArgs e)
{
_serialPort = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
_serialPort.Handshake = Handshake.None;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
// Encoding
//_serialPort.Encoding = Encoding.ASCII;
_serialPort.Encoding = Encoding.Default;
_serialPort.Open();
}
private void btnStart_Click(Object sender, EventArgs e)
{
try
{
if (!_serialPort.IsOpen)
_serialPort.Open();
_serialPort.Write("SI\r\n");
}
catch (Exception ex)
{
MessageBox.Show("Error opening/writing to serial port :: " + ex.Message, "Error!");
}
}
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(2000);
String data = _serialPort.ReadLine();
//String data = _serialPort.ReadByte().ToString();
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new Object[] { data });
}
private void si_DataReceived(String data)
{
textBox1.Text = data.Trim().ToString();
//textBox1.Text = data;
//label1.Text = data;
}
}
How about this?
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
byte[] buf = new byte[spL.BytesToRead];
spL.Read(buf, 0, buf.Length);
string data = System.Text.Encoding.Default.GetString(buf);
}
I am trying to build a simply app that returns the number calling via a modem, however I only seem to be getting the first line of the data received from the modem.
When I run HyperTerminal and pass through the AT#CID=1 command, ring the number, I get a full output of :
OK
DATE=0314
TIME=1111
NMBR=4936
NAME=Stuart E
RING
In my app i only seem to receive the first section containing the "OK" part. Any help on what i am doing wrong or am missing?
Code:
public partial class Form1 : Form
{
public SerialPort port = new SerialPort("COM3", 115200,Parity.None,8,StopBits.One);
public String sReadData = "";
public String sNumberRead = "";
public String sData = "AT#CID=1";
public Form1()
{
InitializeComponent();
}
private void btnRun_Click(object sender, EventArgs e)
{
SetModem();
ReadModem();
MessageBox.Show(sReadData);
}
public void SetModem()
{
if (port.IsOpen == false)
{
port.Open();
}
port.WriteLine(sData + System.Environment.NewLine);
port.BaudRate = iBaudRate;
port.DtrEnable = true;
port.RtsEnable = true;
}
public string ReadModem()
{
try
{
sReadData = port.ReadExisting().ToString();
return (sReadData);
}
catch (Exception ex)
{
String errorMessage;
errorMessage = "Error in Reading: ";
errorMessage = String.Concat(errorMessage, ex.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, ex.Source);
MessageBox.Show(errorMessage, "Error");
return "";
}
}
private void btnExit_Click(object sender, EventArgs e)
{
port.Close();
Close();
}
}
}
In ReadModem() try to use port.ReadLine() in a loop instead and loop until you get a line saying RING (if that is the final line you are expecting).
You are just reading the Modem once after setting it. You need to subscribe the DataReceivedEvent on serialPort to continuously get data from the port.
public void SetModem()
{
if (port.IsOpen == false)
{
port.Open();
}
port.WriteLine(sData + System.Environment.NewLine);
port.BaudRate = iBaudRate;
port.DtrEnable = true;
port.RtsEnable = true;
port.DataReceived += port_DataReceived;
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//For e.g. display your incoming data in RichTextBox
richTextBox1.Text += this.serialPort1.ReadLine();
//OR
ReadModem();
}