Go Down

Topic: Parsing sms messages from sm5100b cellular shield (Read 3084 times) previous topic - next topic

Philherup

Hey,

I have the sparkfun cellular shield hooked up to Deumilanove, I am trying to get data from sms messages added to variables.

By connecting to the cellular module using the sparkfun passthrough sketch and entering command manually through the serial input I can see the response from the get text messages command is this:

+CMGL: 1,0,"REC UNREAD","phonenumber","11/01/08,20:36:09+00"
x,module1,54
+CMGL: 2,0,"REC UNREAD","phonenumber","11/01/08,20:36:27+00"
x,module2,43

So the bit of the first sms I am interested in is the "module1" and "54", ideally what I would like is a variable named module1 set with a value of 54.

The code I have so far, which is mostly from forum member woprbyte:
Code: [Select]
#include <NewSoftSerial.h>  
#include <string.h>        
#define BUFFSIZE 512

char ATBuff[BUFFSIZE];
char SMSBuff[BUFFSIZE];
int CELL_REG = 0;
int CELL_AT = 0;
int CELL_SMSMODE = 0;
int nBufPos;
NewSoftSerial cell(2,3);

void setup()
{
 Serial.begin(9600);
 cell.begin(9600);
 delay(1500);
 Serial.println("starting serial");
}

void loop() {
 while(CELL_REG == 0 || CELL_AT == 0) {            // Keep running loop untill cell network is properly established
   ATGetResp();
   ParseATResp();
 }
 if (digitalRead(8) == HIGH) {                     // On button press, collect sms messages.
   ATGetSMS();
 }
}

void ATGetSMS(void) {
 if (CELL_REG == 1 && CELL_AT == 1) {              // check for cell connection
   if (!CELL_SMSMODE) {                            // if module is not set to text mode change it
     cell.println("AT+CMGF=1");
     CELL_SMSMODE = 1;
     Serial.println("CMFG SET to TEXT");
     
   }
 cell.println("AT+CMGL=\"ALL\"");                  // return all texts from module
 delay(3000);
 ParseSMS();
   
 Serial.println("ATBuff: ");
 Serial.println(ATBuff);
 Serial.println("SMSBuff:");
 Serial.println(SMSBuff);
 }
}

//************************************************************
// Get AT command respnse from the Cell module. Starts and
// ends with CR LF.
//************************************************************
void ATGetResp() {
   char c;
   memset(ATBuff, '\0', BUFFSIZE);                // clear array
   
   nBufPos = 0;                                   // Reset array counter
   int nBytes = 0;                                
   int trigger = 0;
   nBytes = cell.available();                     // Store number of bytes in serial queue
   
   if (nBytes > 0) {
     for (int i = 1; i <= nBytes; i++) {          // Keep running loop till no more bytes in queue
       if (nBufPos == BUFFSIZE - 3) {             // Stop if array is full
         nBufPos = 0;
       }  
       c = cell.read();                           // Set c to current serial character
       if (c == '\r') {                           // If c is carriage return
           ATBuff[nBufPos] = c;                   //   add it to the array
           c = cell.read();                       // Doesnt work without this line, can anyone explain why?
           if (c == '\n') {                       // If c is newline
             ATBuff[nBufPos] = c;                 //   add to array
             ATBuff[nBufPos+1] = '\0';            //   and terminate
             return;                              //   then return to program
           }
       }
       ATBuff[nBufPos] = c;
       nBufPos++;
     }
   
   }
   ATBuff[nBufPos] = '\0';
   return;
}

void ParseSMS() {                                  // This function looks for x the first letter of the message then adds the rest of the message to array
char c;
   memset(SMSBuff, '\0', BUFFSIZE);                
   nBufPos = 0;                                  
   int nBytes = 0;                                
   int trigger = 0;
   nBytes = cell.available();                    
   
   if (nBytes > 0) {
     for (int i = 1; i <= nBytes; i++) {          
       if (nBufPos == BUFFSIZE - 3) {              
         nBufPos = 0;
       }  
       c = cell.read();                          
       
       if (c == 'x' || trigger == 1) {
         trigger = 1;
         SMSBuff[nBufPos] = c;
         c = cell.read();
       }
//        if (c == '\r') {                      
//            SMSBuff[nBufPos] = '\0';    
//            return;                            
//        }
       nBufPos++;
     }
   
   }
   SMSBuff[nBufPos] = '\0';
   return;
}


//************************************************************
// Parse AT Response string
//************************************************************
void ParseATResp(void) {
 if (strstr(ATBuff, "+SIND: 11") != 0) {
   CELL_REG = 1;
   Serial.println("Almost there...");
   return;
 }
 
 if (strstr(ATBuff, "+SIND: 4") != 0) {
   CELL_AT = 1;
   Serial.println("Ready to go!");
   return;
 }
 
 if (strstr(ATBuff, "+SIND: 7") != 0 ||strstr(ATBuff, "+SIND: 8") != 0) {
   CELL_AT = 1;
   Serial.println("Something's wrong.");
   return;
 }      
}


which returns:

starting serial
Almost there...
Ready to go!
CMFG SET to TEXT
ATBuff:
+SIND: 4

SMSBuff:

What I am attempting to do, which clearly isn't working, is when I call for the text messages, look through the incoming serial characters till I see an x, which is what my messages all start with then store what comes after the x in the array, obviously I will need to do something else with it after that, but until I get this bit working I can't do much.

Anyone able to shed any light on my problem?
(my programming skills are pretty limited, so baby steps would be greatly appreciated...)


Phil.

Philherup

So,

I replaced the parsing code with this:

Code: [Select]
void ParseSMS()
{                                
 char c;
 memset(SMSBuff, '\0', BUFFSIZE);                
 nBufPos = 0;                                  

 while(cell.available() > 0)
 {
   c = cell.read();
   if(c == '"')                // looking out for a "
   {
     nBufPos = 0;  
     while(cell.available() > 0 && nBufPos < BUFFSIZE - 3)
     {
       c = cell.read();
       SMSBuff[nBufPos] = c;
       nBufPos++;
     }
   }
 }
 return;
}


Which returns:

starting serial
Almost there...
Ready to go!
CMFG SET to TEXT
ATBuff:
+SIND: 4

SMSBuff:
REC READ","phonenumber","11/01/08,20:36:09+


printing out everything after the first ", but only up to a certain point, there are 3 more character it's not printing.

I'm guessing this has something to do with a buffer being full, but as of yet I don't know where, why or how to make it not happen.


Phil.




Philherup

So I figured out mostly what I needed to, should anyone find this post looking for to solve a similar problem, or stuck with the cellular shield, I documented my progress here http://www.mrphilipgordon.com/blog/tag/cellular-shield/

Or if you're too lazy to read through that, here's is a sketch that should work that you can do with what you will!

Code: [Select]

* Cellular shield code, by Phil Gordon http://mrphilipgordon.com
This code assumes a pull down pushbutton switch attached to pin 9.

Code expects text in the format x,number1,number2 with number1 being either 1 or 2.

It will store number2 in a variable depending on number 1.

Values of variables will be printed on press of pushbutton attached to pin 9

*/




#include <NewSoftSerial.h>         //Include the NewSoftSerial library to send serial commands to the cellular module.
NewSoftSerial cell(2,3);           //Create a 'fake' serial port. Pin 2 is the Rx pin, pin 3 is the Tx pin.

char c = 0;                        //Will hold the incoming character from the Serial Port.
int ATReady = 0;                   //Cellular shield ready
char module1[128];                 //Value for module1
char module2[128];                 //Vue value for module2
int index;                         //Array index
long lastPress = 0;                //For debounce pushbutton
long debounceDelay = 500;          //Delay between represses              


void setup()
{
 Serial.begin(9600);              //Initialize serial ports for communication.
 cell.begin(9600);
 Serial.println("Starting SM5100B Communication...");
}

void loop() {
 if(cell.available() >0)           //If a character comes in from the cellular module...
 {
   c=cell.read();                  //Get the character from the cellular serial port.
   Serial.print(c);                //Print that character to serial monitor
   if(c == '+')                    
   {
     c=cell.read();
     Serial.print(c);
     switch(c)
     {
     case 'S':
       c=cell.read();
       Serial.print(c);
       delay(10);
       c=cell.read();
       Serial.print(c);
       delay(10);
       c=cell.read();
       Serial.print(c);
       delay(10);
       c=cell.read();
       Serial.print(c);
       delay(10);
       c=cell.read();
       Serial.print(c);
       delay(10);
       c=cell.read();
       Serial.print(c);
       switch(c)
       {
       case '3':                                  //Check for initiallisation statud, waiting for command
         Serial.print("\n \rAlmost there...");    //  +SIND: 4
         break;
       case '4':
         Serial.print("\n \rNetwork established");
         ATReady=1;                  
         cell.println("AT+CMGF=1");               //Set message mode to text
         cell.println("AT+CNMI=3,3,0,0");         //Display messages when received
         break;
       case '7':
         Serial.print("\n \rSomething b0rked");
         ATReady=0;
         break;
       }
       break;
     case 'C':
       c=cell.read();
       Serial.print(c);
       delay(10);
       if(c == 'M')
       {
         c=cell.read();
         Serial.print(c);
         delay(10);
         if(c == 'T')
         {
           while(c != 'x')            //Wait untill the character 'x' is displayed
           {
             c=cell.read();
             Serial.print(c);
           }
           c=cell.read();
           Serial.print(c);
           delay(10);
           c=cell.read();
           Serial.print(c);
           switch(c)
           {
           case '1':                  //Run this code if number1 is a 1
             index=0;                 //Reset array index
             c=cell.read();
             Serial.print(c);
             delay(10);
             c=cell.read();
             Serial.print(c);
             while(c != '\r')         //Run loop till end of the line
             {
               module1[index] = c;    //Add character to the array
               c=cell.read();
               Serial.print(c);
               index++;               //Advance array
             }
             module1[index]='\0';     //Terminate array
             break;
           case '2':
             index=0;
             c=cell.read();
             Serial.print(c);
             delay(10);
             c=cell.read();
             Serial.print(c);
             while(c != '\r')
             {
               module2[index] = c;
               c=cell.read();
               Serial.print(c);
               index++;
             }
             module2[index]='\0';              
             break;        
           }

           break;
         }
       }
     }
   }
 }
 if(Serial.available() >0)              //If a character is coming from the terminal to the Arduino...
 {
   c=Serial.read();                     //Get the character coming from the terminal
   cell.print(c);                       //Send the character to the cellular module.
 }

 if (digitalRead(9) == HIGH && (millis() - lastPress) > debounceDelay)   //stop button repeatedly sending commands.
 {
   lastPress = millis();
   Serial.println();
   Serial.print("Module1: ");
   Serial.println(module1);
   Serial.print("Module2: ");
   Serial.println(module2);
 }

}


Philherup

An added note:

Just after I had struggled through figuring all this out, I discovered this alternate shield http://www.hwkitchen.com/products/gsm-playground/

Which seems to have a pretty well stocked library and built in speaker and buzzer and other fun things to go along with it and looks considerably easier to use (I say this having never actually used it mind you!)!

If I could start over I would probably go for the gsm playground version even though it is more expensive.

But I suppose then I would have missed out on this wonderful learning experience!!

Anyway, enough talking to myself for one thread i think!

Hope someone find this useful at some point.


Phil.

zoomkat

In the blog example, the nested testing for +CMTI is interesting as it could be used to identify points to capture data strings from very large web pages.
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

Diastro

Do you have any datasheet for that shield?

Regards,
David

Philherup

The datasheet and command set can be found on the product page at sparkfun

http://www.sparkfun.com/products/9607

Go Up