Offline
Newbie
Karma: 0
Posts: 10
|
 |
« on: March 19, 2012, 09:21:20 am » |
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: if (input == "RING") { digitalWrite... }
The code I'm using atm is: #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
|
|
|
|
|
|
|
Offline
Jr. Member
Karma: 4
Posts: 68
|
 |
« Reply #2 on: March 19, 2012, 10:22:33 am » |
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: /* 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: 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
Full Member
Karma: 0
Posts: 231
|
 |
« Reply #3 on: March 19, 2012, 10:27:25 am » |
ea123, here's the same logic except that it doesn't block. if (phone.available() > 0 && phone.find("\n")) { //... }
|
|
|
|
« Last Edit: March 19, 2012, 10:34:00 am by mkwired »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 10
|
 |
« Reply #4 on: March 19, 2012, 12:14:58 pm » |
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: /* 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
Jr. Member
Karma: 4
Posts: 68
|
 |
« Reply #5 on: March 20, 2012, 03:07:15 am » |
Hi, to compare two strings: #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
Newbie
Karma: 0
Posts: 10
|
 |
« Reply #6 on: March 25, 2012, 02:46:31 pm » |
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. #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
Offline
Brattain Member
Karma: 316
Posts: 35566
Seattle, WA USA
|
 |
« Reply #7 on: March 25, 2012, 03:34:40 pm » |
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. 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
Newbie
Karma: 0
Posts: 10
|
 |
« Reply #8 on: March 25, 2012, 04:03:24 pm » |
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
Offline
Brattain Member
Karma: 316
Posts: 35566
Seattle, WA USA
|
 |
« Reply #9 on: March 25, 2012, 05:04:39 pm » |
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. 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
Newbie
Karma: 0
Posts: 10
|
 |
« Reply #10 on: March 27, 2012, 01:54:13 am » |
Corrected. Unfortunately, I got excited too fast. I'm still getting random response when asking about led status... #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
Offline
Brattain Member
Karma: 316
Posts: 35566
Seattle, WA USA
|
 |
« Reply #11 on: March 27, 2012, 04:24:30 am » |
int index1 = input.indexOf("CC2211"); If input does not contain "CC2211", what will be the value in index1? int index2 = input.length() - 2; If input currently only contains 1 character (which is VERY possible), what will be in index2? 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: 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. 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. Serial.print("Phone's (partial) response: ["); Serial.print(input); Serial.println("]");
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 10
|
 |
« Reply #12 on: March 27, 2012, 10:25:08 am » |
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. #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: 
|
|
|
|
« Last Edit: March 27, 2012, 10:31:10 am by wicket »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 1
|
 |
« Reply #13 on: April 06, 2012, 06:13:54 am » |
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
|
|
|
|
|
|