How to receive more messages from Serial Port c# - c#

I am using System.IO.Ports.
I send messages to device and want to wait for all messages from it.
I am trying do it like this:
message = Console.ReadLine();
_serialPort.Write(message);
Console.WriteLine(_serialPort.ReadExisting());
But it returns only the first line.
I have tried using port.BytesToRead, but I get the same results.
When I use ReadLine() it doesn't return anything.
Edit:
To see all line use Event handler.
Solution for my problem is use \r (enter) on the end line.

ReadExisting return the available bytes available at the exacte time, put a delay befor you read the buffer, a work around would be
message = Console.ReadLine();
_serialPort.Write(message);
Thread.Sleep(200);
Console.WriteLine(_serialPort.ReadExisting());
Edit 2 :
here is how i do it on my projects
private SerialPort port;
string DataReceived = string.Empty;
public string OpenPort(string PortName, int BaudRate)
{
// if the port is already used by other window then return the same instance
if (port != null)
if(port.IsOpen)
return "True";
port = new SerialPort(PortName, BaudRate, Parity.None, 8, StopBits.One);
// Attach a method to be called when there
// is data waiting in the port's buffer
port.DataReceived += new
SerialDataReceivedEventHandler(port_DataReceived);
// Begin communications
try
{
port.Open();
}
catch(Exception ex)
{
return ex.Message;
}
return "True";
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.sleep(200);
DataReceived = port.ReadExisting();
}
in your main
message = Console.ReadLine();
_serialPort.Write(message);
//use Stopwatch to calculate time befor you can exit from the loop
while(true)
{
if(!string.IsNullOrWhiteSpace(DataReceived))
break;
// Todo : Check stopwatch for timeout
}

Maybe you have a new line issue expected from your serial device try:
message = Console.ReadLine();
_serialPort.WriteLine(message);
Console.WriteLine(_serialPort.ReadExisting()); # try debug here replace with string test = _serialPort.ReadLine();

Related

How to handle DataReceived

Please see my code below, that I am trying to return back to method that I registered the port's DataReceived event. Basically, If I recieve data from port before read time out. I will return back where I registered DataReceived event and degister and continue process. I am trying to do it with while loop. But not sure if it is accurate, and it is the way that has to be done
or if there is any other way to do this.
public class CommClass{
private static byte[] portReturn = null;
private void setUpDevice()
{
byte[] command = { 0x11,0X51 };
try
{
port.DataReceived += new SerialDataReceivedEventHandler(serialPortDataReceived);
port.Write(command, 0, command.Length);
while (portReturn == null) { } //Not sure if this will work. If I receive data before times out I do not want to wait in the loop.
port.DataReceived -= serialPortDataReceived;
}
catch(Exception ex)
{
//to do
}
}
private void serialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var servicePort = (SerialPort)sender;
portReturn = servicePort.ReadByte();
return;
}
}
You code will technically work; however, your while loop will max out your CPU while you're waiting for data to come in, which is not what you want. I recommend using a ManualResetEvent here to let you wait to receive data in a CPU friendly way. You can read more about them here
public class CommClass
{
private static byte[] portReturn = null;
// ManualResetEvents are great for signaling events across threads
private static ManualResetEvent dataReceivedEvent = new ManualResetEvent(false);
private void setUpDevice()
{
byte[] command = { 0x11,0X51 };
try
{
port.DataReceived += new SerialDataReceivedEventHandler(serialPortDataReceived);
port.Write(command, 0, command.Length);
// Wait for the event to be set without spinning in a loop.
// Can also specify a timeout period to wait in case the data never comes.
dataReceivedEvent.WaitOne();
// Reset the event so that you can use it again later if necessary
dataReceivedEvent.Reset();
port.DataReceived -= serialPortDataReceived;
}
catch(Exception ex)
{
//to do
}
}
private void serialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var servicePort = (SerialPort)sender;
portReturn = servicePort.ReadByte();
// Set the event to let the main thread know you have received data
dataReceivedEvent.Set();
}
}

Serial COM read returns null [duplicate]

I am developing program which need to interact with COM ports.
By learning from this Q&A: .NET SerialPort DataReceived event not firing, I make my code like that.
namespace ConsoleApplication1
{
class Program
{
static SerialPort ComPort;
public static void OnSerialDataReceived(object sender, SerialDataReceivedEventArgs args)
{
string data = ComPort.ReadExisting();
Console.Write(data.Replace("\r", "\n"));
}
static void Main(string[] args)
{
string port = "COM4";
int baud = 9600;
if (args.Length >= 1)
{
port = args[0];
}
if (args.Length >= 2)
{
baud = int.Parse(args[1]);
}
InitializeComPort(port, baud);
string text;
do
{
String[] mystring = System.IO.Ports.SerialPort.GetPortNames();
text = Console.ReadLine();
int STX = 0x2;
int ETX = 0x3;
ComPort.Write(Char.ConvertFromUtf32(STX) + text + Char.ConvertFromUtf32(ETX));
} while (text.ToLower() != "q");
}
private static void InitializeComPort(string port, int baud)
{
ComPort = new SerialPort(port, baud);
ComPort.PortName = port;
ComPort.BaudRate = baud;
ComPort.Parity = Parity.None;
ComPort.StopBits = StopBits.One;
ComPort.DataBits = 8;
ComPort.ReceivedBytesThreshold = 9;
ComPort.RtsEnable = true;
ComPort.DtrEnable = true;
ComPort.Handshake = System.IO.Ports.Handshake.XOnXOff;
ComPort.DataReceived += OnSerialDataReceived;
OpenPort(ComPort);
}
public static void OpenPort(SerialPort ComPort)
{
try
{
if (!ComPort.IsOpen)
{
ComPort.Open();
}
}
catch (Exception e)
{
throw e;
}
}
}
}
My problem is DataReceived event never gets fired.
My program specifications are:
Just .net console programming
I use VSPE from http://www.eterlogic.com
My computer has COM1 and COM2 ports already.
I created COM2 and COM4 by using VSPE.
I get output result from mystring array (COM1, COM2, COM3, COM4)
But I still don't know why DataReceived event is not fired.
Updated
Unfortunately, I still could not make to fire DataReceived event in any way.
So, I created new project by hoping that I will face a way to solve.
At that new project [just console application], I created a class...
public class MyTest
{
public SerialPort SPCOM4;
public MyTest()
{
SPCOM4 = new SerialPort();
if(this.SerialPortOpen(SPCOM4, "4"))
{
this.SendToPort(SPCOM4, "com test...");
}
}
private bool SerialPortOpen(System.IO.Ports.SerialPort objCom, string portName)
{
bool blnOpenStatus = false;
try
{
objCom.PortName = "COM" + portName;
objCom.BaudRate = 9600;
objCom.DataBits = 8;
int SerParity = 2;
int SerStop = 0;
switch (SerParity)
{
case 0:
objCom.Parity = System.IO.Ports.Parity.Even;
break;
case 1:
objCom.Parity = System.IO.Ports.Parity.Odd;
break;
case 2:
objCom.Parity = System.IO.Ports.Parity.None;
break;
case 3:
objCom.Parity = System.IO.Ports.Parity.Mark;
break;
}
switch (SerStop)
{
case 0:
objCom.StopBits = System.IO.Ports.StopBits.One;
break;
case 1:
objCom.StopBits = System.IO.Ports.StopBits.Two;
break;
}
objCom.RtsEnable = false;
objCom.DtrEnable = false;
objCom.Handshake = System.IO.Ports.Handshake.XOnXOff;
objCom.Open();
blnOpenStatus = true;
}
catch (Exception ex)
{
throw ex;
}
return blnOpenStatus;
}
private bool SendToPort(System.IO.Ports.SerialPort objCom, string strText)
{
try
{
int STX = 0x2;
int ETX = 0x3;
if (objCom.IsOpen && strText != "")
{
objCom.Write(Char.ConvertFromUtf32(STX) + strText + Char.ConvertFromUtf32(ETX));
}
}
catch (Exception ex)
{
throw ex;
}
return true;
}
}
I am not sure that I face good luck or bad luck because this new class could make fire DataReceived event which is from older console application that is still running. It is miracle to me which I have no idea how this happen.
Let me tell you more detail so that you could give me suggestion for better way.
Finally I created 2 console projects.
First project is the class which I posted as a question yesterday.
Second project is the class called MyTest which could make fire DataReceived event from First project, at the same time when two of the project is running.
Could anyone give me suggestions on how could I combine these two projects as a single project?
ComPort.Handshake = Handshake.None;
The problem is not that the DataReceived event doesn't fire, the problem is that the serial port isn't receiving any data. There are very, very few serial devices that use no handshaking at all. If you set it to None then the driver won't turn on the DTR (Data Terminal Ready) and RTS (Request To Send) signals. Which a serial port device interprets as "the machine is turned off (DTR)" or "the machine isn't ready to receive data (RTS)". So it won't send anything and your DataReceived event won't fire.
If you really want None then set the DTREnable and RTSEnable properties to true. But it is likely you want HandShake.RequestToSend since the device appears to be paying attention to the handshake signals.
If you still have trouble then use another serial port program like Putty or HyperTerminal to ensure the connection and communication parameters are good and the device is responsive. SysInternals' PortMon utility gives a low-level view of the driver interaction so you can compare good vs bad.
I have never worked with VSPE so I'm not sure if that causes the problem. I have worked with a COM port before and I looked up my code. The only main difference is the way you declare the event. You have:
ComPort.DataReceived += OnSerialDataReceived;
I have it like this:
ComPort.DataReceived += new SerialDataReceivedEventHandler(OnSerialDataReceived);
OnSerialDataReceived is your eventhandler. I'm not sure if this will make any difference, but you can try it. I hope this helps!
I had a quite similar problem. In a graphical application (C# win form) I had a class which encapsulate a SerialPort component. The DataReceived event was firing only one time, but then any following data received didn't fire any event. I solved the problem by calling the Close method in my principal form Closed event function.
No idea of why that changes anything, but now it's working.

Loop get paused/diactivated inside catch() block

I am trying to send AT commands to COM ports, so I can find the GSM dongle. Below is the code
public bool findGsmModem()
{
bool sendStatus = false;
//Get all the available ports
string[] serialPorts = SerialPort.GetPortNames();
for (int i = 0; i < serialPorts.Length; i++)
{
Console.WriteLine(serialPorts[i]);
}
//Iterate through all the ports sending AT commands to find a modem
for (int i = 0; i < 1; i++)
{
try
{
//port.PortName = serialPorts[i].Trim();
port.PortName = "COM7";
openPort();
string res = ATCommandCaller("AT", 300,"Unable to connect to the phone"); //Connecting to the phone
//res = ATCommandCaller("AT+CMGF=1", 300); //Setting the message Format
sendStatus = true;
break;
}
catch (System.InvalidOperationException ex)
{
//port.PortName = null;
port.Close();
autoInitializer();
//port = new SerialPort();
continue;
//throw ex;
}
}
return sendStatus;
}
Here is how I call this method inside another class
if (sms.findGsmModem())
{
MessageBox.Show("Modem Found: " + sms.getPortName());
}
else
{
MessageBox.Show("No modem found");
}
OK, now in the findGsmModem() method if I use port.PortName = "COM5"; the above second code works successfully and display the message. That is because the Modem is actually in COM5 and the value is hard coded, so the statement do not reach the catch() block.
But, if I use port.PortName = serialPorts[i].Trim(); or port.PortName = serialPorts[i]; then it seems like nothing is happening instead of printing the port names (inside findGsmModem()). Following ports are being printed
COM1
COM2
COM8
COM9
COM5
COM4
COM3
As you can see, the COM5, the port where the gms modem actually exists is in the 5th element of the array, so findGsmModem() calls catch() part before it access the COM5.
I do believe I am not getting anything when port.PortName = serialPorts[i].Trim() is used because it goes to the catch() part and something terrible happens there.
Any idea?
Here is the openPort() method
public void openPort()
{
try
{
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
if (!port.IsOpen)
{
port.Open();
}
port.RtsEnable = true;
port.DtrEnable = true;
}
catch (Exception ex)
{
throw ex;
}
}
EDIT
Here is the most weirdest part. I just noticed the catch() block never get reached when the loop is called! I tried ex.Message to print the stack trace, and it didn't print anything!
catch (Exception ex)
This is the trouble with catch-em-all exception handling. You are getting an InvalidOperationException because you change the PortName property on a opened port. That's a bug in your code, nothing actually went wrong with the serial port.
You'll need to call the Close() method if you find out that it port is not connected to the GSM modem.
Then you can't call Open() again on that same SerialPort instance, it takes time for internal worker thread to shut down. Best thing to do is to create a new instance of SerialPort instead of trying to keep using the same one repeatedly.

C# Serial Communication to Arduino

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.

programming GSM modem in C#

I have a usb gsm modem of type lightWave. I found this code in c# that can receive, send, delete and read sms message from this modem but when a new message arrives to modem, the event that should be raised when new message is received does not get raised. I don't know what the problem is; however, I can read this message from sim after received, but I want the event of received message raised when message arrive this part of code:
private void Form1_Load(object sender, EventArgs e)
{
int port = GsmCommMain.DefaultPortNumber;
int baudRate = 9600; // We Set 9600 as our Default Baud Rate
int timeout = GsmCommMain.DefaultTimeout;
dlg = new frmConnection();
dlg.StartPosition = FormStartPosition.CenterScreen;
dlg.SetData(port, baudRate, timeout);
if (dlg.ShowDialog(this) == DialogResult.OK)
{
dlg.GetData(out port, out baudRate, out timeout);
CommSetting.Comm_Port = port;
CommSetting.Comm_BaudRate = baudRate;
CommSetting.Comm_TimeOut = timeout;
}
else
{
Close();
return;
}
Cursor.Current = Cursors.WaitCursor;
CommSetting.comm = new GsmCommMain(port, baudRate, timeout);
Cursor.Current = Cursors.Default;
CommSetting.comm.PhoneConnected += new EventHandler(comm_PhoneConnected);
CommSetting.comm.MessageReceived += new MessageReceivedEventHandler(comm_MessageReceived);
//....
}
This event does not get raised when message
CommSetting.comm.MessageReceived += new MessageReceivedEventHandler(comm_MessageReceived);
This code in C# I founded at codeproject.com can any help me please?
+CMTI
A GSM/GPRS modem or mobile phone uses +CMTI to notify the computer / PC that a new SMS message has been received and the memory location where it is stored.
keep on run the thread at event handle DataReceivedHandler,
if(indata.Contains("+CMTI"))//Alert for message recived read message from the loacation
Get the loaction and read the message from that specfic sim location.
ref http://www.developershome.com/sms/resultCodes3.asp
ref http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx
first of all you have to make sure that your port, baudRate and time out is valid. And then check comm is properly initialized.
to add handler write the following code only......
comm.MessageReceived += comm_MessageReceived;
and initialize comm by following code.......
comm = new GsmCommMain(port, baudRate, timeout);

Categories