AT Command delivery message c# - c#

I have created winform application to send SMS using USB modem, it working properly but I want to get the delivery message and confirm the message has been sent correctly.
Here is my program
private void button1_Click(object sender, EventArgs e)
{
try
{
SerialPort sp = new SerialPort();
sp.PortName = textBox1.Text;
sp.Open();
sp.WriteLine("AT" + Environment.NewLine);
Thread.Sleep(100);
sp.WriteLine("AT+CMGF=1" + Environment.NewLine);
Thread.Sleep(100);
sp.WriteLine("AT+CSCS=\"GSM\"" + Environment.NewLine);
Thread.Sleep(100);
sp.WriteLine("AT+CMGS=\"" + mobile + "\"" + Environment.NewLine);
Thread.Sleep(100);
sp.Write(message);
Thread.Sleep(100);
sp.Write(new byte[] { 26 }, 0, 1);
Thread.Sleep(100);
var response = sp.ReadExisting();
if (response.Contains("ERROR: 500"))
{
MessageBox.Show("Please check credits");
}
sp.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Please help me how to read the delivery status with above code

This question is not C# specific; rather it's an AT commands question.
After sending a SMS, you'll get a response from modem, something likee this:
+CMGS: {sms id, 0 to 255}
OK
In this case, if Service Center has delivered the SMS successfully, modem will return this response:
+cds: {some id which does not matter} {PDU status report}
You need just decode this PDU to obtain status report, ID of original SMS and other useful data. If the ID of the sent SMS and the one from status report are equal, you have status report exactly for your message.
Note: if you remove message from modem's storage before receiving of delivery report, you'll get report which will be containing all usual information, but status of delivery will be most likely 71 instead of 0.
I used this approach myself, based on this answer, and it works.
Edit 1 :
you are handling the RS232 reading synchronously, which i dont really recomand,the reading function should be fired automatically when the data are available in the port,something like that :
private string SerialDataReceived = string.Empty
private void button1_Click(object sender, EventArgs e)
{
// new instance of the COM port
port = new SerialPort(ComPort, 115200, Parity.None, 8, StopBits.One);
// start port lessener
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
// Begin communications and wait for nad to reboot completly
port.Open();
//send your AT Commands
port.Write("ATE0\r\n");
// check the response 'if Command is successfull it reply with something +Ok'
if(SerialDataReceived.ToLower().Contains("ok"))
}
//event will be fired each time a new data are available in the port
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Show all the incoming data in the port's buffer
SerialDataReceived += port.ReadExisting();
}
now in your send function you should check if you have in the end a response containing +CMGS:,

var response = sp.ReadExisting();
while (!response.Contains("OK") && !response.Contains("ERROR"))
{
// check if message has been sent before exiting
response = sp.ReadExisting();
}

Related

Problem with sending data from c# to arduino for SIM800L

I think I missed something in my code.
Below is my code in C#
public Form1()
{
InitializeComponent();
serialPort1.PortName = "COM2";
serialPort1.BaudRate = 9600;
serialPort1.Parity = Parity.None;
serialPort1.DataBits = 8;
serialPort1.StopBits = StopBits.One;
serialPort1.Handshake = Handshake.RequestToSend;
serialPort1.DtrEnable = true;
serialPort1.RtsEnable = true;
serialPort1.NewLine = System.Environment.NewLine;
}
private void btnSend_Click(object sender, EventArgs e)
{
serialPort1.Open();
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
string num = "+639952006630\n";
serialPort1.Write(num);
string message = "Your child arrived at our school at " + DateTime.Now + ".";
serialPort1.Write(message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Below is my code in Arduino for sending data using GSM module SIM800L
#include <SoftwareSerial.h>
//SIM800 TX is connected to Arduino D8
#define SIM800_TX_PIN 8
//SIM800 RX is connected to Arduino D7
#define SIM800_RX_PIN 7
//Create software serial object to communicate with SIM800
SoftwareSerial serialSIM800(SIM800_TX_PIN,SIM800_RX_PIN);
void setup() {
//Begin serial comunication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
while(!Serial);
//Being serial communication with Arduino and SIM800
serialSIM800.begin(9600);
delay(1000);
//Set SMS format to ASCII
serialSIM800.write("AT+CMGF=1\r\n");
delay(1000);
//getting the number
char remoteNum[20]; // telephone number to send sms
readSerial(remoteNum);
//Send new SMS command and message number
serialSIM800.print("AT+CMGS=\"");
serialSIM800.print(remoteNum);
serialSIM800.print("\"\r\n");
delay(1000);
// getting sms text
char txtMsg[200];
readSerial(txtMsg);
//Send SMS content
serialSIM800.print(txtMsg);
delay(1000);
//Send Ctrl+Z / ESC to denote SMS message is complete
serialSIM800.write((char)26);
delay(1000);
Serial.println("SMS Sent!");
}
/*
Read input serial
*/
char readSerial(char result[]) {
int i = 0;
while (1) {
while (Serial.available() > 0) {
char inChar = Serial.read();
if (inChar == '\n') {
result[i] = '\0';
Serial.flush();
return 0;
}
if (inChar != '\r') {
result[i] = inChar;
i++;
}
}
}
}
void loop() {
}
My confusion/question here is
Whenever I test it using Serial Monitor in Arduino, the code in Arduino sends message to the cellular number successful. But when I use a form in Visual Studio using C#, nothing happens. There are also no errors that appear. I tried F11 also to know if I am missing an error, still I see nothing. But the application does not send SMS to the number.
Help from you guys is very much appreciated. Thank you in advance.
The solution is as obvious as simple. You have all your routines in the Arduino setup which runs only once. So sending one sms from Arduino directly works exactly 1 time.
When connecting via c code, the Arduino is already booted and in the EMPTY loop. So the chance to hit the one time run code is zero.
Put your routines especially
readSerial(remoteNum);
in the loop and it should work as expected.
The first thing you should do before sending the commands with your Visual Studio is that the serialport is correctly configured, you simply have the serial port closed loop, everything you send should receive, If you do not receive anything you have a serial port configuration problem

C# - Example for Handshaking with SerialPort class

I'm currently working on a project which requires me to communicate with an MBED through serial ports.
I've read the msdn site but I don't understand.
Can anyone teach me or show examples of how to use SerialPort.Handshake (XonXoff or RequestToSend)?
My main request how to set: If C# reads a certain string, then send data.
First of all i think that Handshaking is not what you need. Handshaking is a low level communication, to control when to send data or not. more about handshaking
My main request how to set: If C# reads a certain string, then send
data.
What you need is a continuous data reading or an event, and after certain string is read - to send some data.
Let me find some examples.
void connect(){
_port = new SerialPort();
// set port parameters
_port.DataReceived += portDataReceived; //set the data received event
_port.Open();
}
void portDataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting();
if(data.Contains("data-start")) //check for the start data
{
CreateReply(); // your reply
}
}
You can read the data in a while loop, but take a note that an infinite loop executed in the main thread will block your program from responding.
void connectAndRead(){
_port = new SerialPort();
// set port parameters
_port.Open();
_stopReading = false;
var dataBuffer = "";
while(!_stopReading)
{
dataBuffer += _serialPort.ReadLine();
if(!dataBuffer.Contains("data-start")) //check for the start data
continue;
CreateReply(); // your reply
_stopReading = true; // exit loop
}
}

Serial port reading

I am trying to read 3 temperature devices using WinForms and the Modbus 485 protocol.
Basically I have to periodically write a command to each device, wait for response and when I get the response, process it. Each device has a unique communication adress. In order to periodically send the command I am using a timer.Timer1.interval=100;
This is how I am sending the command and where I am processing the response:
private void ProcessTimer_Tick(object sender, EventArgs e)
{
switch (tempState)
{
case TempTimerState.sendCommDevice1:
if (!tempSerial.IsOpen)
{
tempSerial.Open();
}
tempSerial.DiscardInBuffer();
communication.tempCommand[0] = 0x01; //device adress
communication.tempCommand[6] = 0xA5; //CRC
communication.tempCommand[7] = 0xC2; //CRC
tempSerial.Write(communication.tempCommand, 0, 8);
tempState = TempTimerState.recievedDevice1;
communication.waitTime = 0; //time to wait before throw a timeout exception
communication.dataRecievedTemp = false; //flag for response recieved
break;
case TempTimerState.recievedDevice1:
communication.waitTime++;
if (communication.dataRecievedTemp)
{
communication.waitTime = 0;
if(CheckCRC(communication.tempResponse)) //CRC checking
{
//process response
}
else
{
//handle CRC Failure error
}
}
if(commcommunication.waitTime>=maxWaitTime)
{
//handle Timeout exception
}
tempState=TempTimerState.sendCommDevice2;
break;
}
}
and so on for each device. This is my serialport data recieved event:
private void tempSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
sp.Read(communication.tempResponse, 0, sp.BytesToRead);
communication.dataRecievedTemp = true; //flag for data recieved
}
So my communication should be :
send command device1
recieve response device1
send command device2
recieve command device2
send command device3
recieve command device3
and then send command device1 again. The problem is that I get sometimes get communication timeout error and I know for sure that all the devices are responding very quick and every time. Since I had preset the sp.ReceivedBytesThreshold=8I started to get CRC errors too. My response should always be 8 bytes long.
I think the problem is in the serial port data recieved event, but I can't see what's the problem.
P.S. I have also tried to set the timer interval to 1000 miliseconds, but that didn't solve my problem
Relying on ReceivedBytesThreshold is very brittle, the show is over when you get out of sync once. Your code is also very vulnerable to other reasons that DataReceived may fire, you are not checking the e.EventType property. Which certainly can be SerialData.Eof for a binary protocol.
Just write robust code that doesn't depend on the EventType nor the number of available bytes. Like this:
private byte[] rcveBuf = new byte[8];
private int rcveLen;
private void tempSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
rcveLen += sp.Read(rcvebuf, rcveLen, rcveBuf.Length - rcveLen);
if (rcveLen == rcveBuf.Length) {
Array.Copy(rcveBuf, communication.tempResponse, rcveBuf.Length);
communication.dataRecievedTemp = true;
rcveLen = 0;
}
}
And reset rcveLen back to zero on a timeout. And make sure that the timeout isn't too low, you can lose many seconds if your program got swapped out, use 10 seconds to be safe.

Working with SerialPortĀ“s DataReceived Event

Im trying to read the output of a device on a COM port on my PC.
Im wrote a C# program to do so.
Using PuTTY, I can see the output Im expecting from my device.
The problem is that the function SerialPort.ReadExisting(); in my DataReceived function gives my a completely different string.
What is the proper way to read from a COM port using SerialPort?
Also, the strings I get from SerialPort.ReadExisting(); are fragments of the string I sent to the device.
Below is the code that initializes the SerialPort.
SerialPort port;
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = port.ReadExisting();
}
void init_serialport(object sender, EventArgs e)
{
if (port != null)
{
port.Close();
}
port = new SerialPort( /* ... */ );
port.BaudRate = 9600;
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = StopBits.One;
port.Handshake = Handshake.RequestToSend;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
try
{
port.Open();
}
catch (Exception ex)
{
// ...
}
}
the strings I get from SerialPort.ReadExisting(); are fragments of the string I sent to the device.
I'd have a look at SerialPort.ReceivedBytesThreshold.
"Gets or sets the number of bytes in the internal input buffer before a DataReceived event occurs."
I would first take a look at the Read method of the port object, look at the raw bytes and verify that they match your expectations, which would then narrow down the problem to the encoding on the conversion to string.
More information on this is provided here.
You received fragments because SerialPort.Existing() executes and completes in less time then it takes for your sending device to send the entire string.
You need to repeat the call continuously or until you received the end of string character if the string has one.

C#: Timeout on SerialPort.Open?

I have an autodetect thread that tries to open the ports in order and match the received data, thus detecting the port where the relevant device sends the data. Now, there are some ports where the SerialPort.Open simply hangs the thread for ~30 secs. How can I set a timeout on the SerialPort.Open function?
From MSDN
Only one open connection can exist per SerialPort object.
The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.
When you call Close(), this worker thread needs time to spin down and exit. The amount of time needed is not specified and you can't verify that it was done. All you can do is wait at least one second before you call Open() again.
I encountered the same problem and I hope my solution can help you.
You can detect the Serial Ports in a separate thread, which will be aborted in 500 ms.
// the Serial Port detection routine
private void testSerialPort(object obj)
{
if (! (obj is string) )
return;
string spName = obj as string;
SerialPort sp = new SerialPort(spName);
try
{
sp.Open();
}
catch (Exception)
{
// users don't want to experience this
return;
}
if (sp.IsOpen)
{
if ( You can recieve the data you neeed)
{
isSerialPortValid = true;
}
}
sp.Close();
}
// validity of serial port
private bool isSerialPortValid;
// the callback function of button checks the serial ports
private void btCheck(object sender, RoutedEventArgs e)
{
foreach (string s in SerialPort.GetPortNames())
{
isSpValid = false;
Thread t = new Thread(new ParameterizedThreadStart(testSerialPort));
t.Start(s);
Thread.Sleep(500); // wait and trink a tee for 500 ms
t.Abort();
// check wether the port was successfully opened
if (isSpValid)
{
textBlock1.Text = "Serial Port " + s + " is OK !";
}
else
{
textBlock1.Text = "Serial Port " + s + " retards !";
}
}
}
}
Possible improvements could be added into the solution. You can use multi-Thread to accelerate the process and use ProgressBar to display the progress clearly.
Add this in your code:
commPort = new SerialPort();
commPort.ReadTimeout = 1000000;
commPort.WriteTimeout = 1000000;
And I suggest you to see SerialPort.Open Method
If I understood you correctly, you wish to read data from the serial port even after timeout occurred.
If so, then you should catch the TimeoutException and continue your loop. e.g. MSDN CODE
public static void Read()
{
while (_continue)
{
try
{
string message = _serialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}

Categories