How subtract specific letters from String

Hi,

I need help to extract the mobile number from String. Mobile number store in SIM card with start and end mark like #0123456789# and AT command return is
+CPBF: 1,"#00123456789123#",255,"Arduino"

Now I want to get number only my sketch is below. and serial output is like :

+CPBF: 1,"#00XXXXXXXXXX#",255,"Aarduino"
Number is : AT+CPBF="Arduino"
#include <SoftwareSerial.h>
SoftwareSerial SIM900(7, 8);//Configuring the serial pins by software

char c[66] ; //array for midi variables

String readString, substring;
int loc;

void setup()
{
  //Serial connection.
  Serial.begin(9600);
  SIM900.begin(9600);
}

void loop() {

  if (SIM900.available()>0) {
    for (int i = 0; i < 63 ; i++)
    {
      c[i] = SIM900.read();
    }
  //  Serial.println(c);
    if (c == "#") {
      Serial.println(readString); //prints string to serial port out
    
      loc = readString.indexOf("#");
      //Serial.println(loc);
      substring = readString.substring(loc + 12);
      Serial.print("Number is : ");
      Serial.println(substring);

      readString = ""; //clears variable for new input
      substring = "";
    }
    else {
      readString += c; //makes the string readString
    }
    SIM900.println("AT+CPBF=\"Arduino\"");
    delay(1000);
    Serial.print("Number is : ");
    Serial.println(c);
  }
}

// AT command return is :   +CPBF: 1,"#00123456789123#",255,"Arduino"

String number = readString.substring( readString.indexOf("#") + 1 , readString.lastIndexOf("#") ) ;

Strings tend to cause memory problems and crashes with Arduino, so we recommend to avoid them.

Instead, use C-strings (zero terminated character arrays) and the associated functions. strtok() will do what you want.

KASSIMSAMJI:
String number = readString.substring( readString.indexOf("#") + 1 , readString.lastIndexOf("#") ) ;

Thanks for your time , It's working now and solve my problem .

could you please elaborate your code if string is like

+CUSD: 0,"Your balance is 7.53 SR."

how can i use same with position of letters or ".

Thanks

String number = readString.substring( readString.indexOf(""") + 1 , readString.lastIndexOf(""") ) ;

see that backslash before " , yeah , " is one of those in 'escape sequences' in C

warning: Strings have adverse effects to your RAM

KASSIMSAMJI:
String number = readString.substring( readString.indexOf(""") + 1 , readString.lastIndexOf(""") ) ;

see that backslash before " , yeah , " is one of those in 'escape sequences' in C

warning: Strings have adverse effects to your RAM

After slightly change and working.

 String number =  response.substring(response.indexOf("\"") + 1 , response.lastIndexOf("\"") ) ;

But serial output is like

Balance is:*102*#
Balance is:Your balance is 7.53 SR.
Balance is:*102*#
Balance is:*102*#
Balance is:*102*#

I want to display only numbers 7.53 and also not getting every time. My Sketch is below

#include <LiquidCrystal_I2C.h>               //addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

String readString, substring;
String number = "";
char c[34] ; //array for midi variables

#include <SoftwareSerial.h>
char atCommand[80];
char atUssd[16] = "AT+CUSD=1,\"";
char ussdPrefix[16] = "*102*";
char ussdSuffix[3] = "#\"";

SoftwareSerial SIM900(7, 8);

void setup()
{
  Serial.begin(9600);
  SIM900.begin(9600);
  lcd.begin(16, 2);
}

void loop()
{


  if (SIM900.available() > 0) {
    for (int i = 0; i < 33 ; i++)
    {
      c[i] = SIM900.read();

    }
    //  Serial.println(c);
    String response  = c;
    String number =  response.substring(response.indexOf("\"") + 1 , response.lastIndexOf("\"") ) ;
    Serial.print("Balance is:");
    Serial.print(number);
    Serial.println("");
 delay(100);
  }

  strcpy(atCommand, atUssd);
  strcat(atCommand, ussdPrefix);
  strcat(atCommand, ussdSuffix);
  SIM900.println(atCommand);
  delay(3000);
  
  //SIM900.flush();
  // Serial.flush();

}

KASSIMSAMJI:
warning: Strings have adverse effects to your RAM

In my program total 02 ~03 Strings are there is there any bad effect . With this I have enough RAM.

Ghulamfarid:
In my program total 02 ~03 Strings are there is there any bad effect . With this I have enough RAM.

The problem with using the String class (capital S) is that it may work at the start but cause problems after the program has been running for a while because the String class can uses up memory a little piece at a time. Just use cstrings - char arrays terminated with '\0' (NULL).

The parse example Serial Input Basics illustrates the use of strtok(). There is also a function called strstr() that can find one string inside another.

...R

need help to extract the mobile number from String. Mobile number store in SIM card with start and end mark like #0123456789# and AT command return is
+CPBF: 1,"#00123456789123#",255,"Arduino"

wrote a small function based on Robin2`s tutorial.

change delimiter if you need , timeout time , flushing time , add extra filtration etc.

#include <SoftwareSerial.h>

#define input_buffer_size 15

void my_serial_read(char, const char);

const char delimiter = '#';

char phone_number[input_buffer_size];



void setup() {
  
  // put your setup code here, to run once:
  Serial.begin(9600);
  memset(phone_number, '\0', sizeof(phone_number));
  
}

void loop() {
  
if(Serial.available()) my_serial_read(phone_number, delimiter);
 //Serial.println(phone_number);
//delay(5000);
  // put your main code here, to run repeatedly:

}

void my_serial_read(char a[], const char delimiter) {

  char serial_stream = 0;
  signed char  i = 0;
  unsigned long _time = 0;
  bool flag = false;
  const unsigned int timeout = 5000;
  const unsigned int max_time = 1500;
  byte counter = 0;
  _time = millis();

  do {

    if (Serial.available()) {

      serial_stream = Serial.read();

      if (serial_stream == delimiter) {

        flag = true;

        counter++;

      }
      if (flag && (serial_stream!=delimiter)) {

        a[i] = serial_stream;

        (i == (input_buffer_size - 1)) ? i-- : i++;

      }

    }
   
  } while (counter != 2 && (millis() - _time) <= timeout);

  a[i+1] = '\0';

  _time = millis();

  while (millis() - _time < max_time) Serial.read();

  return;
}code]

surepic:
wrote a small function based on Robin2`s tutorial.

change delimiter if you need , timeout time , flushing time , add extra filtration etc.

Thanks Surepic,

I didn't understand completely your sketch but its working for me the only thing is first serial print missing last 04 digits as serial output below

Mobile # is :00XXXXXXX
Mobile # is :00XXXXXXX3839
Mobile # is :00XXXXXXX3839

My current sketch is

#include <SoftwareSerial.h>
SoftwareSerial SIM900(7, 8);//Configuring the serial pins by software

#define input_buffer_size 18

void my_serial_read(char, const char);

const char delimiter = '#';

char phone_number[input_buffer_size];



void setup() {
    Serial.begin(9600);
   SIM900.begin(9600);
      SIM900.println("AT+CPBS=\"SM\"");
    delay(200);
  SIM900.println("AT+CPBF=\"Aarduino\"");
    delay(200);
  // put your setup code here, to run once:

  memset(phone_number, '\0', sizeof(phone_number));

  
}

void loop() {

  
    
if(SIM900.available()) my_serial_read(phone_number, delimiter);
Serial.print("Mobile # is :");
Serial.println(phone_number);
delay(5000);
  // put your main code here, to run repeatedly:

  SIM900.println("AT+CPBF=\"Aarduino\"");
    delay(200);

}

void my_serial_read(char a[], const char delimiter) {

  char serial_stream = 0;
  signed char  i = 0;
  unsigned long _time = 0;
  bool flag = false;
  const unsigned int timeout = 5000;
  const unsigned int max_time = 1500;
  byte counter = 0;
  _time = millis();

  do {

    if (SIM900.available()) {

      serial_stream =SIM900.read();

      if (serial_stream == delimiter) {

        flag = true;

        counter++;

      }
      if (flag && (serial_stream!=delimiter)) {

        a[i] = serial_stream;

        (i == (input_buffer_size - 1)) ? i-- : i++;

      }

    }
   
  } while (counter != 2 && (millis() - _time) <= timeout);

  a[i+1] = '\0';

  _time = millis();

  while (millis() - _time < max_time) SIM900.read();

  return;
}

Robin2:
The parse example Serial Input Basics illustrates the use of strtok(). There is also a function called strstr() that can find one string inside another.
...R

Thanks Robin2,

All of those example are amazing and I am reading that from last few days . I try one of these example which works as expected. But I try to run that function in setup instead of loop and mainly target is to store the number and use as a variable.

How can run it in setup or use stored number in sketch to send SMS.

#include <SoftwareSerial.h>
SoftwareSerial SIM900(7, 8);//Configuring the serial pins by software
// Variable to store text message


const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

// variables to hold the parsed data
char messageFromPC[numChars] = {0};

boolean newData = false;

//============

void setup() {
  Serial.begin(9600);
  SIM900.begin(9600);

  //  pinMode(led, OUTPUT);
  SIM900.print("AT+CMGF=1\r");//AT command to configure the SIM900 in text mode
  delay(200);
  SIM900.print("AT+CNMI=2,2,0,0,0\r");//configure the module to show the SMS through the serial port.
  delay(200);
  SIM900.println("AT+CPBS=\"SM\"");
  delay(200);
  SIM900.println("AT+CPBF=\"Aarduino\"");
  delay(200);
  Serial.println("This demo Start");
  delay(5000);
}

void loop()
{
  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    parseData();
    showParsedData();
    newData = false;
  }
  SIM900.println("AT+CPBF=\"Aarduino\"");
  delay(1000);
}

//============

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '#';
  char endMarker = '#';
  char rc;

  while (SIM900.available() > 0 && newData == false) {
    rc = SIM900.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

//============

void parseData() {      // split the data into its parts
  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars, "#");     // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
}

//============

void showParsedData() {
  Serial.print("Mobile # is : ");
  Serial.println(messageFromPC);
}

Ghulamfarid:
How can run it in setup or use stored number in sketch to send SMS.

The receive functions are not designed to be called from setup() because they may need to run several time before the full message is received.

if you really need to call it from setup() a work-around would be a WHILE loop - for example (check my spelling with the actual examples)

newData = false;
while(newData == false)  {
   receiveWithStartEndMarkers();
}

...R

Robin2:
The receive functions are not designed to be called from setup() because they may need to run several time before the full message is received.

if you really need to call it from setup() a work-around would be a WHILE loop - for example (check my spelling with the actual examples)

newData = false;

while(newData == false)  {
  receiveWithStartEndMarkers();
}




...R

I manage it with one editional boolean operation now its okay and run once in loop.

Last think if you can help me . I want to use this store mobile number to send SMS. but didn't work to send sms.

#include <SoftwareSerial.h>
SoftwareSerial SIM900(7, 8);//Configuring the serial pins by software

const byte numChars = 16;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

// variables to hold the parsed data
char mobileNumber[numChars] = {0};

boolean newData = false;

boolean Mnumber = true;

/////////////////****************//

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '#';
  char endMarker = '#';
  char rc;

  while (SIM900.available()> 0 && newData == false && Mnumber==true) {
    rc = SIM900.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
    
  }
       SIM900.println("AT+CPBF=\"Aarduino\"");
  delay(1000);
  
}

//============

void parseData() {      // split the data into its parts
  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars, "#");     // get the first part - the string
  strcpy(mobileNumber, strtokIndx); // copy it to mobileNumber
}

//============

void showParsedData() {
  Serial.print("Mobile # is : ");   
  Serial.println(mobileNumber);   // Serial print 00123456789123
  Mnumber=false;
}

//============

void setup() {
  Serial.begin(9600);
  SIM900.begin(9600);
  SIM900.print("AT+CMGF=1\r");//AT command to configure the SIM900 in text mode
  delay(200);
  SIM900.print("AT+CNMI=2,2,0,0,0\r");//configure the module to show the SMS through the serial port.
  delay(200);
  SIM900.println("AT+CPBS=\"SM\"");
  delay(200);
  SIM900.println("AT+CPBF=\"Aarduino\"");
  delay(200);
  Serial.println("This demo Start");
  delay(2000);
}

void loop()
{  

     recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
        parseData();
        showParsedData();
         sendSMS();
        newData = false;  
    }     
}



void sendSMS() 
{
  SIM900.println("AT+CMGF=1");    //Sets the GSM Module in Text Mode
  delay(1000);  // Delay of 1000 milli seconds or 1 second
  SIM900.println("AT + CMGS = \"+mobileNumber+\"");
  // SIM900.println("AT + CMGS = \""+mobileNumber+"\""); // Also try not working
  delay(1000);
  SIM900.println("SMS from GSM Module");// The SMS text you want to send
  delay(100);
   SIM900.println((char)26);// ASCII code of CTRL+Z
  delay(1000);
  Serial.println("MSG Send");
}

Serial monitor

This demo Start
Mobile # is : 0012345678910
MSG Send
while (SIM900.available()> 0 && newData == false && Mnumber==true) {

Don't mess with the code within recvWithStartEndMarkers()

Instead make a test in loop() like this

void loop() {
   if (Mnumber == true) {
      recvWithStartEndMarkers();
   }
   // other stuff
}

Separately, in general do not include a test in a WHILE which involves a variable that is never changed within the WHILE loop.

I have no knowledge of SIM devices.

...R

Yes clear.

I will try to stored the number in EEPROM which seem to be flexible to use in sketch or keypad input.

Here is link I found "Write String to Arduino EEPROM"