Pages: [1]   Go Down
Author Topic: Arduino/GSM Communication - Capturing data  (Read 2284 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi!

I've successfully build a project like this - Old Sony Ericsson phone as GSM shield.



My goal is to send an SMS both ways - from my phone to Sony Ericsson, which is connected to Arduino and the other way around. And this works with no problem but I get stuck, when I have to read and further interprate incoming AT responses, so that I could control some relays or sth based on SMS content.

For example let's say I'm communicating through putty:

I make a call from my phone to SE and get a response "RING".



Now, when doing the same thing through Arduino, I'd have to store this "READ" into some string (?) variable, but can't figure out the way to do it. So further on I could do something like:

Code:
if (input == "RING") {
     digitalWrite...
}

The code I'm using atm is:
Code:
#include <SoftwareSerial.h>

// phone connected to pins 2,3 so it doesn't interfere with arduino
SoftwareSerial phone(2,3);

void setup ()
{
  // serial connection
  Serial.begin(9600);
  Serial.println("Arduino connected.");
  delay(500);
  
  // phone serial connection
  phone.begin(9600);
  Serial.println("Ericsson T610 connected.");
  delay(1000);
  
  // začetna inicializacija mobitela
  Serial.println("Initialization...");
  delay(100);
  phone.println("AT+CPMS=\"ME\",\"ME\""); // internal phone storage use
  delay(1000);
  phone.println("AT+CMGF=0"); // PDU mode
  delay(1000);
  phone.println("AT+CNMI=2,3,0,0,0"); // transfering incoming data directly to terminal
  delay(1000);
  Serial.println("Done.");
  phone.flush();
}

void loop ()
{
  // read phone response
  if (phone.available() > 0)
  {
    char sms = phone.read();
    Serial.print(sms);
  }
}

This way I get "RING" response, but it's not stored anywhere since it takes each char seperately.



Could I somehow use serialEvent()? I've tried, but no success.

Thanks.
« Last Edit: March 19, 2012, 09:29:57 am by wicket » Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Use one or more of the Stream member functions.

http://arduino.cc/en/Reference/Stream
Logged

Offline Offline
Jr. Member
**
Karma: 4
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
you have to build the string one character at a time by storing them in a temporary buffer. What you need to know is the end of transmission character (probably a new-line). Try a function like this:

Code:
/* Get a string from serial port until newline character */
void getSerialInput(char *buff, int buffSize )
{
   int i = 0;
   do
   {
      while( !Serial.available() );

      if( (buff[i] = (char) Serial.read()) == 13 )
      {
         break;
      }
     
      i++;
   }
   while( i < buffSize-1);
   
   buff[i] = '\0';
}

usage:

Code:
   const int N_CHAR = 16;
   char tmp[N_CHAR];
   // ...
   getSerialInput(tmp, N_CHAR);

Note that the function blocks the loop execution until an end of line is received.
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ea123, here's the same logic except that it doesn't block.

Code:
if (phone.available() > 0 && phone.find("\n"))
{
   //...
}
« Last Edit: March 19, 2012, 10:34:00 am by mkwired » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ea123, I tried your code and I get RING written, when i call tmp variable.

How do I make a condition now, sth like if (tmp == "RING") ... ?

Also, could I use serialEvent() similar way as used in this example:

Code:
/*
  Serial Event example
 
 When new serial data arrives, this sketch adds it to a String.
 When a newline is received, the loop prints the string and
 clears it.
 
 A good test for this is to try it with a GPS receiver
 that sends out NMEA 0183 sentences.
 
 Created 9 May 2011
 by Tom Igoe
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/SerialEvent
 
 */

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}
« Last Edit: March 19, 2012, 12:19:23 pm by wicket » Logged

Offline Offline
Jr. Member
**
Karma: 4
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
to compare two strings:

Code:
#include <string.h>

   if( !strcmp( tmp, "RING" ) )
   {
      // ....
   }

The serialEvent function is simply called after loop() when a data is available on the receive buffer, so you can use it in the same way: save each received character in a char array and set to TRUE the "stringComplete" flag  when the end of string is detected.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, that works, now I have another problem.

I'm using 3 SMS commands: "LED ON" (turns the led on), "LED OFF" (turns the led off), "LED STATE" (tells me back the current state of the led).

When I send it "LED STATE", I get the reply, but it's always telling me that led is off, even if it's actually on. Am I not storing it's state in a variable properly, is it something wrong with those 2 if statement that include state == x, or why is this code (below) not working?

Please, help.

Code:
#include <SoftwareSerial.h>

SoftwareSerial phone(2,3);       // phone connected to pins 2,3

const int ledPin = 13;          
String input;                

void setup ()
{
  // LED pin
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // serial comm
  Serial.begin(9600);
  Serial.println("Arduino connected.");
  delay(200);

  //phone comm
  phone.begin(9600);
  Serial.println("Ericsson T610 connected.");
  delay(500);

  // phone init
  Serial.println("Begin init...");
  phone.println("AT+CPMS=\"ME\",\"ME\""); // phone memory
  delay(2000);
  phone.println("AT+CMGF=0");             // PDU type
  delay(2000);
  phone.println("AT+CNMI=2,3,0,0,0");     // send data to terminal
  delay(2000);
  phone.flush();
  Serial.println("End of init, waiting for SMS...");
}

void loop ()
{
  while (phone.available() == 0);    

  do                          
  {
    input += String((char)phone.read());
  }
  while (phone.available() > 0);

  Serial.println(input);                  // phone answer to commands
 
  boolean state = digitalRead(ledPin);   // reading the current state of the LED

  int index1 = input.indexOf("CC2211");  
  int index2 = input.length() - 2;  
 
  if (input.substring(index1,index2) == "CC2211645D329F50") digitalWrite(ledPin, HIGH);  // "LED ON"
  if (input.substring(index1,index2) == "CC221194D42E994F28") digitalWrite(ledPin, LOW); // "LED OFF"
 
  if ((input.substring(index1,index2) == "CC221134A5069DCA22") && (state == 1))         // "LED STATE" case: high
  {
    phone.println("AT+CMGD=1");             // delete old SMS on memory place 0
    delay(2000);    
    phone.println("AT+CMGW=37");            // write SMS in memory
    delay(2000);
    phone.print("07918346011033F301000B918336XXXXXXXX00001B4139B99E76BF7520669108529741F635FB0D67ABCBEEB00B"); // SMS in PDU
    delay(3000);
    phone.write(26);                        // Ctrl + Z
    delay(2000);
    phone.println("AT+CMSS=1");             // send SMS
    delay(2000);
  }
 
  if ((input.substring(index1,index2) == "CC221134A5069DCA22") && (state == 0))         // "LED STATE" case: low
  {
    phone.println("AT+CMGD=1");             // delete old SMS on memory place 0
    delay(2000);
    phone.println("AT+CMGW=38");            // write SMS in memory
    delay(2000);
    phone.print("07918346011033F301000B918336XXXXXXXX00001C4139B99E76BF752066910852974169FD9AFD86B3D56577D805");
    delay(3000);
    phone.write(26);                        // Ctrl + Z
    delay(2000);
    phone.println("AT+CMSS=1");             // send SMS
    delay(2000);
  }
 
  input = "";                               // reset input variable
}

PS: I have no problems turning led on and off.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49386
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Reading an output pin is not the best way to determine if the pin is on or off. You set the pin state. Remember what you set it to.

Code:
  do                           
  {
    input += String((char)phone.read());
  }
  while (phone.available() > 0);
Horridly inefficient to create an instance of the String class, then invoke the copy constructor and the append operator and the String destructor, to append a String, when the append operator knows how to append a char.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tnx Paul, I didn't know I can't read the output pin. It works now.

About that String fail - I know it's a disaster, but it is the only way I could make it read and print out phones response. I tried everything suggested in recent replys, but could't get it to work OK.

Could you be a bit more specific with your proposed solution?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49386
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

phone is an instance of SoftwareSerial. SoftwareSerial::read() returns an int. But, the reason for returning an int is so that it can return an error condition. By calling phone.available() first (you aren't, by the way), you ensure that read() never needs to return an error condition. Therefore, the real data returned by read() can go in a byte or a char, whichever is appropriate for the type of data being read.

Code:
while(phone.available() > 0)
{
   char aChar = phone.read();
   input += aChar;
}

Notice that there is a big difference between while and do/while. Read up on the differences, if you need to.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Corrected.

Unfortunately, I got excited too fast. I'm still getting random response when asking about led status...

Code:
#include <SoftwareSerial.h>

SoftwareSerial phone(2,3);       // phone connected to pins 2,3

const int ledPin = 13;           
String input;       
int state = 0;        // flag LED indicator

void setup ()
{
  // LED pin
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // serial comm
  Serial.begin(9600);
  Serial.println("Arduino connected.");
  delay(200);

  //phone comm
  phone.begin(9600);
  Serial.println("Ericsson T610 connected.");
  delay(500);

  // phone init
  Serial.println("Begin init...");
  phone.println("AT+CPMS=\"ME\",\"ME\""); // phone memory
  delay(2000);
  phone.println("AT+CMGF=0");             // PDU type
  delay(2000);
  phone.println("AT+CNMI=2,3,0,0,0");     // send data to terminal
  delay(2000);
  phone.flush();
  Serial.println("End of init, waiting for SMS...");
}

void loop ()
{
  while (phone.available() == 0);   

  while (phone.available() > 0)
  {
    char aChar = phone.read();
    input += aChar;
  }

  Serial.println(input);                  // phone answer to commands

  int index1 = input.indexOf("CC2211"); 
  int index2 = input.length() - 2;   
 
  if (input.substring(index1,index2) == "CC2211645D329F50")
  {
     digitalWrite(ledPin, HIGH);  // "LED ON"
     state = 1;   // set flag to "1"
  }

  if (input.substring(index1,index2) == "CC221194D42E994F28")
  {
     digitalWrite(ledPin, LOW); // "LED OFF"
     state = 0;  // set flag to "0"
  }
 
  if ((input.substring(index1,index2) == "CC221134A5069DCA22") && (state == 1))         // "LED STATE" case: high
  {
    phone.println("AT+CMGD=1");             // delete old SMS on memory place 1
    delay(2000);     
    phone.println("AT+CMGW=37");            // write SMS in memory
    delay(2000);
    phone.print("07918346011033F301000B918336XXXXXXXX00001B4139B99E76BF7520669108529741F635FB0D67ABCBEEB00B"); // SMS in PDU
    delay(3000);
    phone.write(26);                        // Ctrl + Z
    delay(2000);
    phone.println("AT+CMSS=1");             // send SMS
    delay(2000);
  }
 
  if ((input.substring(index1,index2) == "CC221134A5069DCA22") && (state == 0))         // "LED STATE" case: low
  {
    phone.println("AT+CMGD=1");             // delete old SMS on memory place 1
    delay(2000);
    phone.println("AT+CMGW=38");            // write SMS in memory
    delay(2000);
    phone.print("07918346011033F301000B918336XXXXXXXX00001C4139B99E76BF752066910852974169FD9AFD86B3D56577D805");
    delay(3000);
    phone.write(26);                        // Ctrl + Z
    delay(2000);
    phone.println("AT+CMSS=1");             // send SMS
    delay(2000);
  }
 
  input = "";                               // reset input variable
}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49386
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  int index1 = input.indexOf("CC2211"); 
If input does not contain "CC2211", what will be the value in index1?

Code:
  int index2 = input.length() - 2;   
If input currently only contains 1 character (which is VERY possible), what will be in index2?

Code:
  if (input.substring(index1,index2) == "CC2211645D329F50")
  {
     digitalWrite(ledPin, HIGH);  // "LED ON"
     state = 1;   // set flag to "1"
  }
Do you suppose that it is smart to call substring with negative values for the start position or length?

If input IS "CC221134A5069DCA22", you have a lot of duplicate code. The tests involving this value should be nested, to reduce the amount of duplicate code:
Code:
if(input.substring(index1,index2) == "CC221134A5069DCA22")
{
   // Do some common stuff
   if(state == 1)
   {
      // Do state 1 stuff
   }
   else if(state == 0)
   {
      // Do state 0 stuff
   }
   else
   {
      // Do unknown state stuff
   }
   // More common stuff
}

You have not shown us the output you are seeing on the Serial Monitor, so it's really hard to help you.
Code:
Serial.println(input);                  // phone answer to commands
The comment is incorrect. The stuff in input is potentially only PART OF the phone's answer. Printing some identifying/bracketing information is usually quite useful.
Code:
Serial.print("Phone's (partial) response: [");
Serial.print(input);
Serial.println("]");
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, I've taken some of your ideas into consideration and I've come up with this so far.

Problems remains the same - I can turn led on/off, but I always get the same response when asking about it's current state.

Code:
#include <SoftwareSerial.h>

SoftwareSerial phone(2,3);       // phone connected to pins 2,3

const int ledPin = 13;           // LED on pin 13
String input;                    // phones response is saved into this string
int state = 0;                   // current state of the LED

void setup ()
{
  // Serial connection
  Serial.begin(9600);
  Serial.println("Arduino connected.");
  delay(200);

  // phone connection
  phone.begin(9600);
  Serial.println("Ericsson T610 connected.");
  delay(500);
  
  // LED pin init
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // phone init
  Serial.println("Start of phone init...");
  phone.println("AT+CPMS=\"ME\",\"ME\",\"ME\"");   // phone memory used for SMS storage
  delay(2000);
  phone.println("AT+CNMI=2,3,0,0,0");              // forward all received stuff into terminal window
  delay(2000);
  phone.flush();
  Serial.println("End of init. Waiting for command SMS...\n");
}

void loop ()
{  
  while (phone.available() == 0);         // waiting for phones response  

  while (phone.available() > 0)           // read incoming data from phone and save it into input string
  {
    char aChar = phone.read();
    input += aChar;
  }

  // phones (partial) response displayed in serial window
  Serial.println(input);

  // "decoding" received SMS
  int index1 = input.indexOf("CC2211");
  int index2 = input.length() - 2;
  
  // if received SMS "LED ON" turn on LED
  if (input.substring(index1,index2) == "CC2211F47402")
  {
    digitalWrite(ledPin, HIGH);
    state = 1;
  }
  
  // if received SMS "LED OFF" turn off LED
  else if (input.substring(index1,index2) == "CC2211F4341A01")
  {
    digitalWrite(ledPin, LOW);
    state = 0;
  }
  
  // if received SMS "LED STATE" check for LED state and reply with SMS
  else if (input.substring(index1,index2) == "CC221134A506A945")
  {
    phone.println("AT+CMGD=1");               // delete old SMS in memory place 1      
    delay(2000);
    
    if (state == 1)                           // if LED is turned ON
    {
      phone.println("AT+CMGW=36");            // SMS length in octets (PDU)
      delay(2000);
      phone.print("07918346011033F301000B918356613xxxxx00001A4139B99E76BF75206691084ACF41F4BADC5D26839E4E17"); // SMS "Arduino: LED is ON." in PDU format
      delay(3000);
    }
    else if (state == 0)                      // if LED is turned OFF
    {
      phone.println("AT+CMGW=37");            // SMS length in octets (PDU)
      delay(2000);
      phone.print("07918346011033F301000B918356613xxxxx00001B4139B99E76BF75206691084ACF41F4BADC5D26839E46A30B"); // SMS "Arduino: LED is OFF." in PDU format
      delay(3000);
    }
    
    phone.write(26);                          // Ctrl + Z
    delay(2000);                            
    phone.println("AT+CMSS=1");               // send SMS stored in memory place 1
    delay(2000);
  }
  
  input = "";                                 // reset input string
}

Image shows, how the conversation is made.



Yellow font shows what's happening with LED.

Step 1&2: I send LED STATE and get reply: LED is turned OFF.
Step 3: I send LED ON and led turns on.
Step 4&5: I send LED STATE again and get the same reply as before, evendo variable state changed it's value to 1 (I've checked).

So I definitely step into other if loop. This could only mean, something unexpected is going on inside the phone itself. Now I've noticed that I'm not getting a response from AT+CMGD=1 command back into Serial, but it should respond OK. This is supposed to delete old SMS in memory place #1, so next time I could save another content in that same place. Also a part of PDU message, which appears after > is missing, but that doesn't matter since I do get the SMS with full content back. I have no idea why isn't it working, since I have no problem using the same series of AT commands from terminal (putty) directly.

Serial window:



 smiley-sad smiley-sad

« Last Edit: March 27, 2012, 10:31:10 am by wicket » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

First of all: Why do you use PDU mode??
SE T610 supports text mode.

To start text mode, send: AT+CMGF=1
And then to send SMS:
AT+CMGS=”<phone number>”
This is sample SMS content<Ctrl+z>

Logged

Pages: [1]   Go Up
Jump to: