Parsing sms messages from sm5100b cellular shield

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:

#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.

So,

I replaced the parsing code with this:

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.

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!

* 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);
  }

}

An added note:

Just after I had struggled through figuring all this out, I discovered this alternate shield ​Váš parťák ve světě tvoření | HWKitchen.cz

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.

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.

Do you have any datasheet for that shield?

Regards,
David

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