Reading GPS with for loops, gps.read()

I have some code below that I am using to determine GPS location, by determining the amount of data in my serial buffer using gps.avaiable(), i then use that to create a string of the buffer size. When i try to write to that string in my for loop below, it works perfectly fine about six or seven times. Then randomly starts incrementing my for loop index almost exponentially? I really have no clue why this would be happening. My function below gets called about 6 or seven times, then you can see in my output where the for loop crashes.

void readGPS()
{
  int numchars =  0;
  int index = 0;
  char *myString;

  numchars = gps.available();
  Serial.println("numchars");
  Serial.println(numchars);
  myString[0] = '\0';
  
  if(numchars == 63)
  {
    myString = calloc(numchars, sizeof(char));
    for(index; index < numchars - 3; index++) //(numchars > 0)
    {
      Serial.print(index);
      Serial.print(",");
      myString[index] = gps.read();
    }
    myString[numchars - 1] = 0;
    myString[numchars] = '\0';
    Serial.println(myString);
  }
  return;
}

You can see below here I am printing out the index of my for loop, and at the end you see in bold the index of my for loop changing crazily then the serial quits responding.

I can post my full code if necessary, but everything in my code works just fine, until i run this function.

numchars
63
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,3
$GPRMC,235755.00,A,2342.343451,N,134513.1345134,W,0.474,,1011
numchars
3
numchars
63
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,3
$GPRMC,235755.00,A,2342.343451,N,134513.1345134,W,0.474,,1011
numchars
9
numchars
63
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,3
$GPRMC,235755.00,A,2342.343451,N,134513.1345134,W,0.474,,1011
numchars
63
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,3
numchars
63
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,3
numchars
3
numchars
63
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,3
$GPRMC,235755.00,A,2342.343451,N,134513.1345134,W,0.474,,1011
numchars
3
numchars
63
0,1,2*
u`,3,4,5,6,7,8,68,11333,3288134,858926151,858926152,858926153,858926154,858926155,858926156,858926157,858926158,

  char *myString;

myString is going to point to a character (or the first character of an array of characters). Fine.

  myString[0] = '\0';

Uh oh. myString is not pointing to anything specific, but whatever it happens to be pointing to is going to be overwritten by a zero.

I also see a call to calloc(...) to allocate numchars bytes of memory, but then

    myString[numchars] = '\0';

puts a zero in the location past the end of the allocation (arrays are zero-based).

Strange and undefined things are likely to happen. You could corrupt data and/or corrupt code. You have only provided a snippet of your code, so I cannot tell if you have made other errors elsewhere.

In addition to the problems pointed out by vaj4088, this section will cause problems:

 numchars = gps.available();
  Serial.println("numchars");
  Serial.println(numchars);

Every time you call readGPS, it prints about 9 characters. We can't see all your code, but if you are calling this from loop(), it will get called tens of thousands of times per second. That means you are trying to print hundreds of thousands of characters per second, just with this section. Depending on the Serial baud rate, your program will get stuck at these prints, waiting for the debugging characters to be sent to the PC.

While the Serial.println is waiting to send "numchars" to the PC, the GPS device continues to send NMEA characters to the Arduino. Eventually, the input buffer overflows and GPS characters are dropped.

When the Serial.print finally processes the 's' of "numchars", it returns to your sketch... which then prints the integer numchars as something like "63", a '6' character and a '3' character. That takes more time, and more GPS characters are dropped.

The point is that you can't print this much debugging information. The GPS device keeps sending characters, and your sketch has to keep reading them, or the input buffer overflows.

There are some pictures on the NeoGPS Troubleshooting page, like I mentioned in your other post.

You should also look at the NMEAloc.ino example. It is a simple sketch that prints out the location, once per second. It shows the proper loop structure, and has several comments about the best places to do "things". If you want to try it, you can now use the Library Manager to install NeoGPS. NMEAloc will be available in the examples -> NeoGPS menu of the IDE.

Cheers,
/dev

Here is all my code.... I made some edits after what errors you told me I would be having but I am still getting trouble with the same thing. I can get my function readGPS() to run exactly 10 times and then everything goes weird on me and breaks. Any other help would be greatly appreciated.

#include <XBee.h>
#include <Wire.h>
#include <SparkFunMPL3115A2.h>
#include <SPI.h>
#include <SparkFunLSM9DS1.h>
#include <SoftwareSerial.h> //XBEE Comms
#include <SD.h>

SoftwareSerial XBee(0, 1); // RX, TX (0 and 1 are the TX/RX pins on the Fio v3)
SoftwareSerial gps(11, 1);

MPL3115A2 altimeter;
LSM9DS1 accelerometer;

#define LSM9DS1_M 0x1E //I2C addresses of the LSM9DS1
#define LSM9DS1_AG 0x6B
#define PRINT_CALCULATED

const int chipSelect = 10;
const long startTime = millis();
float acceleration = 0;
int index = 0; 
int i = 0;
float V1;
float V2;
float altitudeArray[3];
long timeArray[3];
String NMEA;

void setup()
{
  accelerometer.settings.device.commInterface = IMU_MODE_I2C;
  accelerometer.settings.device.mAddress = LSM9DS1_M;
  accelerometer.settings.device.agAddress = LSM9DS1_AG;

  gps.begin(9600);
  XBee.begin(9600);  
  accelerometer.begin();
  altimeter.begin();

  altimeter.setModeAltimeter();
  altimeter.setOversampleRate(7);
  altimeter.enableEventFlags();
  
  if (!SD.begin(chipSelect))
  {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  
  
  XBee.println("start");
}


void loop() 
{
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    float altitude = altimeter.readAltitudeFt();
    float temperature = altimeter.readTempF();
    long milliSecondsPassed = millis() - startTime;

    acceleration = getAcceleration(altitude, index, milliSecondsPassed); // (altimeter.readAltitudeFt() / Time);
    index++;

    if(index > 2)
    {
      index = 0;
    }
  
    XBee.println("Altitude");
    XBee.println(altitude);
    XBee.println("Acceleration");
    XBee.println(acceleration);
    XBee.println("Temperature");
    XBee.println(temperature);

    readGPS(gps.available());

    delay(100);
    dataFile.close();
}

float getAcceleration(float altitude, int index, long milliSecondsPassed)
{
  float acceleration;
  
  altitudeArray[index] = altitude;
  timeArray[index] = milliSecondsPassed;
  
  if(index == 2)
  {    
    V1 = (altitudeArray[1] - altitudeArray[0])/(timeArray[1] - timeArray[0]);
    V2 = (altitudeArray[2] - altitudeArray[1])/(timeArray[2] - timeArray[1]);
    acceleration = (V2 - V1)/(timeArray[2] - timeArray[0]);
  }
  else
  {
    acceleration = 0; 
  }

  return acceleration; 
}

static void readGPS(const int numChars)
{
  int index = 0;
  char *myString;
  
  if(numChars == 63)
  {
    myString = calloc(numChars, sizeof(char));
    
    for(index; index < numChars - 3; index++)
    {
      Serial.print(index);
      Serial.print(",");
      myString[index] = gps.read();
    }
    myString[numChars - 2] = 0;
    myString[numChars - 1] = '\0';
    Serial.println(myString);
  }
  return;
}

myString = calloc(numChars, sizeof(char));You would be much better off just declaring myString to be a fixed size array, global if need be and reuse it as necessary.

You fail to check for a NULL return from calloc(). Keep in mind that memory management on an Arduino is far from perfect.

Yep, 10 * numChars = 630 bytes of RAM. You've used most of it up after 10 loops.

You should try something simpler, first. Start with Serial Input Basics on the Useful Links page. See if you can store a GPS line and print it out. That example shows you how to declare an array and fill it as the characters come in, without using delay. Your sketch has many problems related to that timing.

Cheers,
/dev

SoftwareSerial XBee(0, 1); // RX, TX (0 and 1 are the TX/RX pins on the Fio v3)
SoftwareSerial gps(11, 1);

Why are you trying to use SoftwareSerial on the hardware serial pins?

Why are you trying to use Serial without calling the Serial.begin() method?

/dev:
Yep, 10 * numChars = 630 bytes of RAM. You've used most of it up after 10 loops.

You should try something simpler, first. Start with Serial Input Basics on the Useful Links page. See if you can store a GPS line and print it out. That example shows you how to declare an array and fill it as the characters come in, without using delay. Your sketch has many problems related to that timing.

Cheers,
/dev

The tutorial for serial input helped me a ton!! thank you very much!