Problems with Arduino and SIM808

I was working with an Arduino uno and a SIM808 shield (not from arduino) to make an automated lock with GPS. The lock was supposed to respond to SMS representing orders which would be opening or closing the lock and sending back and SMS confirming its done, and would use a GPS antenna to get their current location ans send it to a web server. Here is the code I used:

#include <MemoryFree.h>
#include <SoftwareSerial.h>

SoftwareSerial SIM808(7, 8); // Configures Rx and Tx in that order
String mensaje = "";
char incoming_char = 0;

void setup()
   {
      pinMode(2, OUTPUT);
      pinMode(3, OUTPUT);
      pinMode(11, OUTPUT);
      pinMode(12, INPUT);
      pinMode(13, INPUT);
      SIM808.begin(9600);
      Serial.begin(9600);
      iniciar(); //method to configure the SIM808
   }

void loop()
  {
    if (SIM808.available()) {
      incoming_char = SIM808.read(); //Save characters of GPRS
      Serial.print(incoming_char); //Shows character in serial monitor
      mensaje = mensaje + incoming_char ;
      mensaje_sms(); //method with the app's main functionality

      }
    }
    
int enviarAT(String ATcommand, char* resp_correcta, unsigned int tiempo)
{

  int x = 0;
  bool correcto = 0;
  char respuesta[100];
  unsigned long anterior;

  memset(respuesta, '\0', 100);
  delay(100);
  while ( SIM808.available() > 0) SIM808.read();
  SIM808.println(ATcommand);
  x = 0;
  anterior = millis();
  do {
    if (SIM808.available() != 0)
    {
        respuesta[x] = SIM808.read();
        x++;
      if (strstr(respuesta, resp_correcta) != NULL)
      {
        correcto = 1;
      }
    }
  }
  while ((correcto == 0) && ((millis() - anterior) < tiempo));
  Serial.println(respuesta);
  return correcto;
}

void iniciar()
{
  while ( enviarAT("AT+CREG?", "+CREG: 0,1", 1000) == 0 ) //Checks the connection with the GPRS network
  {
  }
  enviarAT("AT+CLIP=1\r", "OK", 1000); //Activates call identification
  enviarAT("AT+CMGF=1\r", "OK", 1000); // Activates SMS functionality
  enviarAT("AT+CNMI=2,2,0,0,0\r", "OK", 1000); //Lets SMS be shown in the Serial Monitor
  enviarAT("AT+CGPSPWR=1\r","OK",1000); //Activates GPS module
  enviarAT("AT+CGATT=1\r", "OK", 1000); //Connects to the internet through GPRS
  enviarAT("AT+CSTT=\"internet.comcel.com.co\",\"comcel\",\"comcel\"", "OK", 3000); //Defines APN
  enviarAT("AT+CIICR", "OK", 3000); //Activates wireless data profile
  enviarAT("AT+CIFSR", "", 3000); //Gets IP address
}

void mensaje_sms()
{
  int abrir = mensaje.indexOf("Orden 1 PIN 0000");
  int cerrar = mensaje.indexOf("Orden 2 PIN 0000");
  int estado = mensaje.indexOf("Orden 3 PIN 0000");
  bool modo = 0;
  char sms[] = "";
  char aux_str[50];

  if (abrir >= 0){
      modo = 1;
      } else {
        if (cerrar >= 0){
          modo = 0;
          } 
        }

  if (abrir >= 0 || cerrar >= 0)
  {
    if(enviarAT("AT+CREG?", "+CREG: 0,1", 1000) == 1){
    enviarAT("AT+CMGF=1\r", "OK", 1000);
    sprintf(aux_str, "AT+CMGS=\"XXXXXXXXXX\"", strlen(sms));//SMS writing mode
    if (enviarAT(aux_str, ">", 10000) == 1)
    {
      if (abrir >= 0){
      SIM808.println("Orden 1 Cumplida PIN 0000");
      abrir  = -1;
      while(digitalRead(13) == LOW){
              analogWrite(11,200);
              digitalWrite(2,HIGH);
              digitalWrite(3,LOW);
            }
              digitalWrite(11,LOW);
              digitalWrite(2,LOW);
              digitalWrite(3,LOW);
      }
      if (cerrar >= 0){
        SIM808.println("Orden 2 Cumplida PIN 0000");
        cerrar = -1;
        while(digitalRead(12) == LOW){
              analogWrite(11,200);
              digitalWrite(2,LOW);
              digitalWrite(3,HIGH);
            }
              digitalWrite(11,LOW);
              digitalWrite(2,LOW);
              digitalWrite(3,LOW);
      }
      
      delay(100);
      SIM808.println((char)26);
    }
    mensaje = "";
    
    }
  }
  if (estado >= 0){
    reportar(modo);
    estado = -1;
  }
}


void reportar(bool modo)
{
  int gcount = 0;
  int gflag = 0;
  long antes;
  char gpsdata[200];
  char latitud[15];
  char longitud[15];
  
  while(Serial.available()>0) Serial.read();
  Serial.println(freeMemory());
  enviarAT("AT+CGPSINF=0\r","OK",2000); //Gets GPS data
  Serial.println(freeMemory());
  memset(gpsdata,'\0',100);
  antes=millis();
  do{
    if(Serial.available()!=0){
      gpsdata[gcount]=Serial.read();
      gcount++;
      if(strstr(gpsdata,"OK")!=NULL){
        gflag=1;
      }
    }
  }while((gflag==0) && ((millis()-antes)<2000));
  gpsdata[gcount - 3]='\0';

  strtok(gpsdata, ",");
  strcpy(latitud, strtok(NULL, ","));
  strcpy(longitud , strtok(NULL, ","));
  strtok(NULL, ",");
  strtok(NULL, ",");
  strtok(NULL, ",");
  strtok(NULL, ",");
  strtok(NULL, ",");
  strtok(NULL, "\r");

  String tlatitud(atof(latitud));
  String tlongitud(atof(longitud));
  
  if (enviarAT("AT+CREG?", "+CREG: 0,1", 1000) == 1)
  {
    String url = "GET http://bicicity.mba-software.com/geo_report.php?dev=3137336311&lt="+ tlatitud + "&lg=" + tlongitud + " HTTP/1.0\r\n\r\n"; //HTTP GET request
    String men = String(url.length());
    String envio = "AT+CIPSEND="+ men + "\r\n"; //Mode for writing the data being sent
    enviarAT("AT+CIPSTART=\"TCP\",\"bicicity.mba-software.com\",\"80\"\r","CONNECT OK",5000); //Initiates TCP connection with server
      if(enviarAT(envio, ">", 2000)){
        enviarAT(url,"SEND OK",10000);
  }
    
  }
}

Now, the part about opening and closing the lock worked perfectly. The problems arise with the GPS functionality especifically. On the first hand, the method I used to extract the response from the AT Command that gets the GPS data (based on a code from this site: https://www.cooking-hacks.com/documentation/tutorials/how-to-display-latitude-and-longitude-on-lcd-gprs-gps/) isn't working at all: it is supposed to get the response of the AT command as a char array and then tokenize it, but when the code reaches that part, it gets a void array, thus when I reformat the data, it becomes zeroes. It doesn't matter where I'm located.
However, the main Issue with the code is that it either freezes or resets the moment it tries to send the GET request (sometimes it crashes earlier). I tried to see the memory usage at that point with freeMemory() and it showed a value that I think does't make sense (over 13000), so I tried to reduce the number of global variables, as the code used to have more, but it didn't work.

Am I missing something? Or perhaps an Arduino UNO is not powerful enough?

P:S: I'm powering both devices (Arduino and SIM808) with independent power supplies as the Arduino can't supply enough current to te SIM808.

it gets a void array

It can't possibly get a void array. It CAN get an empty array, but that is NOT the same as an array of type void.

Please do not post code full of commented out code. The commented out code is obviously NOT part of the problem. Delete it before posting code.

    if (SIM808.available()) {
      incoming_char = SIM808.read(); //Guardamos el carácter del GPRS
      Serial.print(incoming_char); //Mostramos el carácter en el monitor serie
      mensaje = mensaje + incoming_char ;
      mensaje_sms();

Having read one character, why is it necessary to call mensaje_sms()?

  char sms[] = "";

You've created an array that can hold 0 characters. How is THAT useful?

    sprintf(aux_str, "AT+CMGS=\"XXXXXXXXXX\"", strlen(sms));

sms is NOT a string (because there is not room to hold even the NULL terminator, so you should not be passing it to a function that expects a string.

The do/while statement in enviarAT(), in which you have an if statement that makes sure that the do/while statement does nothing, is NOT appropriate. Use a while statement.

  while(Serial.available()>0) Serial.read();

Why is it necessary to ensure that the incoming serial buffer is empty?

The do/while statement in reportar(), in which you have an if statement that makes sure that the do/while statement does nothing, is NOT appropriate. Use a while statement.

  strtok(gpsdata, ",");
  strcpy(latitud, strtok(NULL, ","));
  strcpy(longitud , strtok(NULL, ","));

You must ALWAYS check that strtok() returned a valid pointer.

The lack of comments in your code make it very difficult to follow the complete flow, if you are not intimately familiar with all the AT commands.

Providing some serial output would be useful. It is difficult to tell that you ever actually sent the SMS to cause the GPS to be read. More Serial.print() statements in reportar() would be useful, too.

Thanks for the reply Paul. Now, about you observations:

PaulS:
It can't possibly get a void array. It CAN get an empty array, but that is NOT the same as an array of type void.

Right, wrong concept. My bad, still according to the code from the cooking hacks link, I should get a char array with valid characters, not an empty array.

PaulS:
Please do not post code full of commented out code. The commented out code is obviously NOT part of the problem. Delete it before posting code.

Got it. I edited my first post to remove all the commented code.

PaulS:

  char sms[] = "";

You've created an array that can hold 0 characters. How is THAT useful?

    sprintf(aux_str, "AT+CMGS=\"XXXXXXXXXX\"", strlen(sms));

sms is NOT a string (because there is not room to hold even the NULL terminator, so you should not be passing it to a function that expects a string.

Both are related. Those parts of the code and plenty of others are part from tutorials from this site: SIM808: GSM/GPRS + GPS – Prometec (Warning: It's in spanish). For those to specific parts, now that I think about it, aren't really useful...I could just send the AT command directly with enviarAT() and be done with the sms variable entirely.

PaulS:
The do/while statement in enviarAT(), in which you have an if statement that makes sure that the do/while statement does nothing, is NOT appropriate. Use a while statement.

  while(Serial.available()>0) Serial.read();

Why is it necessary to ensure that the incoming serial buffer is empty?

The do/while statement in reportar(), in which you have an if statement that makes sure that the do/while statement does nothing, is NOT appropriate. Use a while statement.

Those 3 parts are parts of codes from the links provided in this and my previous message. I didn,t alter them as they worked fine, but if using a normal while statement could decrease memory usage, I can try it.

PaulS:

  strtok(gpsdata, ",");

strcpy(latitud, strtok(NULL, ","));
strcpy(longitud , strtok(NULL, ","));



You must ALWAYS check that strtok() returned a valid pointer.

The response from AT+CGPSINF=0 is like this: "+CGPSINF: 0,4316.645000,257.667700,14.800000,20170117141311.000,0,9,1.796440,198.850006". The first code block after variable declarations in reportar() are supposed to save that string in the gpsdata array but a Serial.print of that array showed nothing in the Serial Monitor.

First, I made this modification before the tokenization:

Then, after running the code and sending the message, this happens:

The line that reads "Orden 3 PIN 0000AT+CGPSINF=0" is the sms sent followed inmediatly by the AT command that gets GPS data (despite looking wrong, you can see that up to that point, everything works ). Then after the ACK of the AT command's response (which is filled with zeroes as I'm in a place with bad reception and I don't have screenshots of the test with proper GPS data but that ended similarly) you can see an empty space between the freeMemory() prints. Finally, after the "CONNECT OK" line, the program crashed. This is the code I first posted on this topic.

After applying the changes suggested by PaulS, eliminating the variables that no longer matter due to that and changing the url string to "GET http://bicicity.mba-software.com/geo_report.php?dev=3137336311&lt="+ tlatitud + "&lg=" + tlongitud + " HTTP/1.0\r\nConnection: close\r\n\r\n", the program reached a further point than before. However, now just as the program is sending the GET request, the program resets:

The number just befor the AT+CIPSEND=114 line is a freeMemory() print.