Extracting GPS data from sentence without a library

I found an example code that does almost exactly what I want, but it appears to have a glitch. What I need is to extract: LatLong, GPS heading, Speed, SatNumber, DOP, GPStime and make a string to send via sms.
The code extracts some of them, but when it prints everything via serial the old strings get concatenated with the new ones...

This is the code:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3,2);   //software serial instance for GPS/GSM module
String latlongtab[5];  // for the purpose of example let array be global
#define DEBUG true 
String state, timegps, latitude, longitude;
void setup() {
  
  mySerial.begin(9600);
  Serial.begin(9600);           //open serial port
  delay(50);
  
  /*We can use old sendData function to print our commands*/
  sendData("AT+CGNSPWR=1",1000,DEBUG);       //Initialize GPS device
  delay(50);
  sendData("AT+CGNSSEQ=RMC",1000,DEBUG);
  delay(150);
}
void loop() {
   sendTabData("AT+CGNSINF",1000,DEBUG);    //send demand of gps localization
   if(state != 0){
    /*we just dont want to print empty signs so we wait until 
     * gps module will have connection to satelite.
    
     * when whole table returned:
   for(int i = 0; i < (sizeof(latlongtab)/sizeof(int)); i++){
      Serial.println(latlongtab[i]); // print 
    }*/
    Serial.println("State: "+state+" Time: "+timegps+"  Latitude: "+latitude+" Longitude "+longitude);
   }else{
    Serial.println("GPS initializing");
   }
   
}
void sendTabData(String command, const int timeout, boolean debug){
 
    mySerial.println(command); 
    long int time = millis();
    int i = 0;   
    
    while((time+timeout) > millis()){
      while(mySerial.available()){       
        char c = mySerial.read();
        if(c != ','){ //read characters until you find comma, if found increment
          latlongtab[i]+=c;
          delay(100);
        }else{
          i++;        
        }
        if(i == 5){
          delay(100);
          goto exitL;
        }       
      }    
    }exitL:    
    if(debug){ 
      /*or you just can return whole table,in case if its not global*/ 
      state = latlongtab[1];     //state = recieving data - 1, not recieving - 0
      timegps = latlongtab[2];
      latitude = latlongtab[3];  //latitude
      longitude = latlongtab[4]; //longitude
    }    
}
String sendData(String command, const int timeout, boolean debug){
  
    String response = "";    
    mySerial.println(command); 
    long int time = millis();
    int i = 0;  
     
    while( (time+timeout) > millis()){
      while(mySerial.available()){       
        char c = mySerial.read();
        response+=c;
      }  
    }    
    if(debug){
      Serial.print(response);
    }    
    return response;
}

And here's the serial output:

State: 1 Time: 20181017153156.000 Latitude: -33.207455 Longitude -33.8931
State: 11 Time: 20181017153156.00020181017153202.000 Latitude: -33.207455-33.207472 Longitude -33.8931-33.893
State: 111 Time: 20181017153156.00020181017153202.00020181017153208.000 Latitude: -33.207455-33.207472-33.207473 Longitude -33.8931-33.893-33.893.

The module is a SIM808 GSM/GPS

does this fix it?
(added latlongtab[i]= "";)

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3,2);   //software serial instance for GPS/GSM module
String latlongtab[5];  // for the purpose of example let array be global
#define DEBUG true 
String state, timegps, latitude, longitude;
void setup() {
  
  mySerial.begin(9600);
  Serial.begin(9600);           //open serial port
  delay(50);
  
  /*We can use old sendData function to print our commands*/
  sendData("AT+CGNSPWR=1",1000,DEBUG);       //Initialize GPS device
  delay(50);
  sendData("AT+CGNSSEQ=RMC",1000,DEBUG);
  delay(150);
}
void loop() {
   sendTabData("AT+CGNSINF",1000,DEBUG);    //send demand of gps localization
   if(state != 0){
    /*we just dont want to print empty signs so we wait until 
     * gps module will have connection to satelite.
    
     * when whole table returned:
   for(int i = 0; i < (sizeof(latlongtab)/sizeof(int)); i++){
      Serial.println(latlongtab[i]); // print 
    }*/
    Serial.println("State: "+state+" Time: "+timegps+"  Latitude: "+latitude+" Longitude "+longitude);
    latlongtab[1] = "";
    latlongtab[2] = "";
    latlongtab[3] = "";
    latlongtab[4] = "";
    latlongtab[5] = "";
   }else{
    Serial.println("GPS initializing");
   }
   
}
void sendTabData(String command, const int timeout, boolean debug){
 
    mySerial.println(command); 
    long int time = millis();
    int i = 0;   
    
    while((time+timeout) > millis()){
      while(mySerial.available()){       
        char c = mySerial.read();
        if(c != ','){ //read characters until you find comma, if found increment
          latlongtab[i]+=c;
          delay(100);
        }else{
          i++;        
        }
        if(i == 5){
          delay(100);
          goto exitL;
        }       
      }    
    }exitL:    
    if(debug){ 
      /*or you just can return whole table,in case if its not global*/ 
      state = latlongtab[1];     //state = recieving data - 1, not recieving - 0
      timegps = latlongtab[2];
      latitude = latlongtab[3];  //latitude
      longitude = latlongtab[4]; //longitude
    }    
}
String sendData(String command, const int timeout, boolean debug){
  
    String response = "";    
    mySerial.println(command); 
    long int time = millis();
    int i = 0;  
     
    while( (time+timeout) > millis()){
      while(mySerial.available()){       
        char c = mySerial.read();
        response+=c;
      }  
    }    
    if(debug){
      Serial.print(response);
    }    
    return response;
}

or this

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3,2);   //software serial instance for GPS/GSM module
String latlongtab[5];  // for the purpose of example let array be global
#define DEBUG true 
String state, timegps, latitude, longitude;
void setup() {
  
  mySerial.begin(9600);
  Serial.begin(9600);           //open serial port
  delay(50);
  
  /*We can use old sendData function to print our commands*/
  sendData("AT+CGNSPWR=1",1000,DEBUG);       //Initialize GPS device
  delay(50);
  sendData("AT+CGNSSEQ=RMC",1000,DEBUG);
  delay(150);
}
void loop() {
   sendTabData("AT+CGNSINF",1000,DEBUG);    //send demand of gps localization
   if(state != 0){
    /*we just dont want to print empty signs so we wait until 
     * gps module will have connection to satelite.
    
     * when whole table returned:
   for(int i = 0; i < (sizeof(latlongtab)/sizeof(int)); i++){
      Serial.println(latlongtab[i]); // print 
    }*/
    Serial.println("State: "+state+" Time: "+timegps+"  Latitude: "+latitude+" Longitude "+longitude);
   }else{
    Serial.println("GPS initializing");
   }
   
}
void sendTabData(String command, const int timeout, boolean debug){
 
    mySerial.println(command); 
    long int time = millis();
    int i = 0;   
    
    while((time+timeout) > millis()){
      while(mySerial.available()){       
        char c = mySerial.read();
        if(c != ','){ //read characters until you find comma, if found increment
          latlongtab[i]+=c;
          delay(100);
        }else{
          i++;        
        }
        if(i == 5){
          delay(100);
          goto exitL;
        }       
      }    
    }exitL:    
    if(debug){ 
      /*or you just can return whole table,in case if its not global*/ 
      state = latlongtab[1];     //state = recieving data - 1, not recieving - 0
      latlongtab[1]= "";
      timegps = latlongtab[2];
      latlongtab[2]= "";
      latitude = latlongtab[3];  //latitude
      latlongtab[3]= "";
      longitude = latlongtab[4]; //longitude
      latlongtab[4]= "";
    }    
}
String sendData(String command, const int timeout, boolean debug){
  
    String response = "";    
    mySerial.println(command); 
    long int time = millis();
    int i = 0;  
     
    while( (time+timeout) > millis()){
      while(mySerial.available()){       
        char c = mySerial.read();
        response+=c;
      }  
    }    
    if(debug){
      Serial.print(response);
    }    
    return response;
}

Mostly probably. Those indexes on latlongtab should be 0 to 4 though, not 1 to 5.

@lenny227 your second option works, thank you!

After a while the serial monitor stops outputting data, it just creates a new line, I suspect it might be because of memory problems due to the strings... Any ideas? There's also a glitch that makes the longitude data come without the last numbers and instead prints a point.

Serial output:
State: 1 Time: 20181017165122 LatLong: -33.207265 -33.8931
State: 1 Time: 20181017165128 LatLong: -33.207278 -33.893.

-33.207298 -33.8931

Can you tell me what you get if you replace

Serial.println("State: "+state+" Time: "+timegps+"  Latitude: "+latitude+" Longitude "+longitude);
with Serial.println(latlongtab[5]);[/code?

lenny227:
Can you tell me what you get if you replace

Serial.println("State: "+state+" Time: "+timegps+"  Latitude: "+latitude+" Longitude "+longitude);

with Serial.println(latlongtab[5]);[/code?

If you print the element at position 5 of an array with 5 elements, you'll get garbage.

OP: Quit using Strings. There is NOTHING you cab do with a String that you can not do with a string.

If you print the element at position 5 of an array with 5 elements, you'll get garbage.

That's what happened... Any other suggestions?

I have the felling that this code could be a little cleaner, it's somehow simple but not easy to read what it's doing.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);  //software serial instance for GPS/GSM module
String DataGPS[5];  // for the purpose of example let array be global
#define DEBUG true
String state, timegps, LatLong, Alt ;
void setup() {

  mySerial.begin(9600);
  Serial.begin(9600);           //open serial port
  delay(50);

  /*We can use old sendData function to print our commands*/
  sendData("AT+CGNSPWR=1", 1000, DEBUG);     //Initialize GPS device
  delay(50);
  sendData("AT+CGNSSEQ=RMC", 1000, DEBUG);
  delay(150);
}
void loop() {
  sendTabData("AT+CGNSINF", 1000, DEBUG);  //send demand of gps localization
  if (state != 0) {
    /*we just dont want to print empty signs so we wait until
       gps module will have connection to satelite.

       when whole table returned:
      for(int i = 0; i < (sizeof(latlongtab)/sizeof(int)); i++){
      Serial.println(latlongtab[i]); // print
      }*/
    Serial.println("State: " + state + " Time: " + timegps + "  LatLong: " + LatLong);
  } else {
    Serial.println("GPS initializing");
  }

}
void sendTabData(String command, const int timeout, boolean debug) {

  mySerial.println(command);
  long int time = millis();
  int i = 0;

  while ((time + timeout) > millis()) {
    while (mySerial.available()) {
      char c = mySerial.read();
      if (c != ',') { //read characters until you find comma, if found increment
        DataGPS[i] += c;
        delay(100);
      } else {
        i++;
      }
      if (i == 5) {
        delay(100);
        goto exitL;
      }
    }
} exitL:
  if (debug) {
    /*or you just can return whole table,in case if its not global*/
    state = DataGPS[1];     //state = recieving data - 1, not recieving - 0
    DataGPS[1] = "";
    timegps = DataGPS[2];
    timegps.remove(14);
    DataGPS[2] = "";
    LatLong = DataGPS[3];  //latitude
    DataGPS[3] = "";
    LatLong += ' ';
    LatLong += DataGPS[4]; //longitude
    DataGPS[4] = "";
  }
}
String sendData(String command, const int timeout, boolean debug) {

  String response = "";
  mySerial.println(command);
  long int time = millis();
  int i = 0;

  while ( (time + timeout) > millis()) {
    while (mySerial.available()) {
      char c = mySerial.read();
      response += c;
    }
  }
  if (debug) {
    Serial.print(response);
  }
  return response;
}

Any other suggestions?

Don't print beyond the end of any array.

Quit using Strings.

Quit using goto.

Quit using delay() in the loop to read GPS data.

Stop adding times.

Use a library that someone that knows what they are doing has written, until you know what you are doing, which you clearly do not (yet).

The reason I was avoiding to use a library is because the serial communication is for AT commands and not standard serial, thus I don’t know how the library would communicate with the board. And goto, delay... were there because it wasn’t my code, I just found it. What is the suggestion about the library?

The reason I was avoiding to use a library is because the serial communication is for AT commands and not standard serial, thus I don't know how the library would communicate with the board.

All of the GPS parsing libraries require that YOU get the data, one character at a time, from the GPS and pass the character to the library. Whether you get that data from Serial, Serial1, a software serial instance, or make sh*t up, is irrelevant.

And goto, delay... were there because it wasn't my code, I just found it.

Well, you should have kept looking then. That code is crap.

So, let's use TinyGPS++, I have tried enabling an AT command to output the raw GNSS sentences to serial, like a normal serial GNSS module would do, and tell the library to parse the data, but I had no success... TinyGPS++ | Arduiniana

AT+CGNSPWR=1 enables the GNSS receiver

AT+CGNSTST=1 enables GNSS test mode which outputs data like this:

$GPGGA,142655.000,8888.8888,S,08888.8888,W,1,8,1.01,847.8,M,-3.7,M,,40
$GPGLL,8888.8888,S,08888.8888,W,142655.000,A,A
57
$GPGSA,A,3,17,07,13,15,06,30,19,05,,,,,1.27,1.01,0.7806
$GPGSV,4,1,13,17,72,076,23,13,64,240,34,19,59,008,20,30,39,098,21
79
$GPGSV,4,2,13,28,37,152,25,15,24,228,46,05,13,310,15,07,13,076,2974
$GPGSV,4,3,13,06,10,021,17,12,04,290,32,01,03,118,16,24,03,233,32
78
$GPGSV,4,4,13,11,02,135,4E
$GPRMC,142655.000,A,8888.8888,S,08888.8888,W,0.07,332.30,241018,,,A
68
$GPVTG,332.30,T,,M,0.07,N,0.13,K,A*39

#include <SoftwareSerial.h>
#include <TinyGPS++.h>


#define TX 3
#define RX 2
#define PHONE_NUMBER 88888888888
#define Wait 1000
SoftwareSerial mySerial(TX, RX);
TinyGPSPlus gps;
unsigned long previousMillis;


void TrackAndTell();

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  while (mySerial.read() != "OK") {
    mySerial.print("AT+CGNSPWR=1");
  }
  delay(1000);
  while (mySerial.read() != "OK") {
    mySerial.print("AT+CGNSTST=1");
  }

}

void loop() {
  if (millis() - previousMillis >= Wait) {
    TrackAndTell();
    previousMillis = millis();
  }
  while (mySerial.available() > 0)
    gps.encode(mySerial.read());

}


void TrackAndTell() {

  Serial.print("LAT=");  Serial.println(gps.location.lat(), 6);
  Serial.print("LONG="); Serial.println(gps.location.lng(), 6);
  Serial.print("ALT=");  Serial.println(gps.altitude.meters());

}
  if (millis() - previousMillis >= Wait) {
    TrackAndTell();
    previousMillis = millis();
  }
  while (mySerial.available() > 0)
    gps.encode(mySerial.read());

It is pointless to call TrackAndTell() before gps.encode() returns true. It is equally pointless to ignore the value returned by gps.encode().

That said, I no longer understand what your problem is.

So, let's use TinyGPS++, I have tried enabling an AT command to output the raw GNSS sentences to serial, like a normal serial GNSS module would do, and tell the library to parse the data, but I had no success...

That conveys as little information as "it didn't work" but does use bigger words.

Something happened that only you can see (or not see, as you don't print what you get from the GPS). You expected something to happen. All that we can surmise is that what happened is not what you wanted.

My problem is that I can't get the data to be parsed by the library.

caiopoit:
My problem is that I can't get the data to be parsed by the library.

How do you know that? The code you posted silently collects (or not) data from the GPS and passed the data to the encode() method for processing. You don't know what the GPS is sending, or what the encode() method is returning.

  while (mySerial.available() > 0)
  {
    char c = mySerial.read();
    Serial.print(c);
    if(gps.encode(c))
    {
       Serial.println("The end of the GPS sentence arrived. The data was parsed");
    }
  }

With this code, you'll have facts and data. Facts and data are better then guesses any day of the week.

Still returning nothing... How do I make sure the GNSS started sending its sentences after the AT command?

#include <SoftwareSerial.h>
#include <TinyGPS++.h>


#define TX 3
#define RX 2
#define PHONE_NUMBER 88888888888
#define Wait 1000
SoftwareSerial mySerial(TX, RX);
TinyGPSPlus gps;
unsigned long previousMillis;


void TrackAndTell();

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  delay(1000);
  sendATcommand("AT+CGNSPWR=1", "OK", 2000);
  delay(1000);
  sendATcommand("AT+CGNSTST=1", "OK", 2000);
  //  }

}

void loop() {
  /*
    while (mySerial.available()) {
      gps.encode(mySerial.read());
      Serial.write(mySerial.read());
    }*/
  while (mySerial.available() > 0)
  {
    char c = mySerial.read();
    Serial.print(c);
    if (gps.encode(c))
    {
      Serial.println("The end of the GPS sentence arrived. The data was parsed");
    }
  }
  if (millis() - previousMillis >= Wait ) {
    TrackAndTell();
    previousMillis = millis();
  }
}


void TrackAndTell() {
  mySerial.print("AT+CGNSPWR=1");
  mySerial.print("AT+CGNSTST=1");
  Serial.print("LAT=");  Serial.println(gps.location.lat(), 6);
  Serial.print("LONG="); Serial.println(gps.location.lng(), 6);
  Serial.print("ALT=");  Serial.println(gps.altitude.meters());

}

int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialice the string

  delay(100);

  while ( Serial.available() > 0) Serial.read();   // Clean the input buffer

  if (ATcommand[0] != '\0')
  {
    Serial.println(ATcommand);    // Send the AT command
  }


  x = 0;
  previous = millis();

  // this loop waits for the answer
  do {
    if (Serial.available() != 0) {  // if there are data in the UART input buffer, reads it and checks for the asnwer
      response[x] = Serial.read();
      //Serial.print(response[x]);
      x++;
      if (strstr(response, expected_answer) != NULL)    // check if the desired answer (OK) is in the response of the module
      {
        answer = 1;
      }
    }
  } while ((answer == 0) && ((millis() - previous) < timeout));   // Waits for the asnwer with time out

  return answer;
}

I got something, now serial outputs data:

$GPGSA,A,3,12,24,15,25,,,,,,,,,3.16,2.99,1.00*03
The end of the GPS sentence arrived. The data was parsed

$GPGSV,2,1,05,24,59,220,44,19,44,152,24,12,32,226,46,15,29,304000,A,2888.4402,S,04888.5940,W,1.95,268.71,21018,,,A66
$GPVTG,268.71,T,,M,1.95,N,3.61,K,A
3E
The end of the GPS sentence arrived. The data was parsed

LAT=-88.807336
LONG=-88.893234
ALT=858.90

caiopoit:
I got something, now serial outputs data:

So, you're happy? Or, do you still have problems?

What changed? Just adding code to print more information didn't make the GPS start working.

So, you're happy? Or, do you still have problems?

Yes I'm happy, got what I wanted.