0
votes

I'm working on a GPS logger project. I have an Arduino Mega set up with a transmitter and receiver and GPS and GSM modules. I also have an Arduino Uno with a transmitter, receiver and buzzer.

When the two devices go too far from each other, the GPS data is pulled and sent to my web server using the GSM module. When I send my file to the server it creates a text file and when I move to another location it overwrites the previous location.

I'm trying to figure out how to append the text file instead of overwriting it. I found a lot of stuff using an SD card shield but nothing without it.

#define GPS_PIN_1       9       // GPS serial pin RX
#define GPS_PIN_2       8       // GPS serial pin TX
#define CHECKPIN        13      // Pin that lights up when things are checked
#define GPSRATE         4800    // GPS baud rate

#include <SoftwareSerial.h>
#include <Flash.h>
#include <Streaming.h>

// How many bytes of input to buffer from the GPS?
#define BUFFERSIZE      100      
#define ENDLN           

int rx1Pin=31; 
int txPin=30;  
int tx1Pin=11;  
int onModulePin = 2;
int rxPin=12;
SoftwareSerial mySerial = SoftwareSerial(GPS_PIN_1, GPS_PIN_2);  //(rx,tx)
SoftwareSerial txSerial = SoftwareSerial(rxPin, txPin);
SoftwareSerial rxSerial = SoftwareSerial(rx1Pin, tx1Pin);
char sendChar ='H';
char incomingChar = 0;
int counter=0;

//GPS variables
int numSats = 0;
int fixType = 0;
int time[] = {
  0, 0, 0};
double latitude = 0.0;
double longitude = 0.0;
long altitude = 0;
long maxAlt = 0;
int speed = 0;
int txCount = 0;
int ExOnce = 0;
int FalcomCheck = 0;
int LogCheck =0;
unsigned long GpsOffTime = 0;  
unsigned long SmsStart = 0;     // SMS-time
char buffer[BUFFERSIZE];

void switchModule(){            // Function to switch the module ON;
  digitalWrite(onModulePin,HIGH);
  delay(2000);
  digitalWrite(onModulePin,LOW);
  delay(2000);
}

void setup(){
  pinMode(rxPin, INPUT);
  pinMode(txPin,OUTPUT);
  pinMode(rx1Pin, INPUT);
  pinMode(tx1Pin,OUTPUT);
  pinMode(GPS_PIN_1, INPUT);
  pinMode(GPS_PIN_2, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(7, HIGH);
  pinMode(onModulePin, OUTPUT);

  txSerial.begin(4800);
  rxSerial.begin(4800);
  mySerial.begin(4800);
  Serial.begin(19200);      // The GPRS baud rate
  switchModule();           // Switch the module ON

  for (int i=0;i<2;i++){    // Wait 20 sec for connection
    delay(10000);                        
  } 
}

void loop(){
  txSerial.println(sendChar);
  Serial.println(sendChar);

  for(int i=0; i<6; i++) {
    incomingChar = rxSerial.read(); //Read incoming message from TX.

    if (incomingChar =='L') {
      GPS();//Serial.println("It Works");
    }
  }
}

void GPS(){
  Serial.flush();

  // Get a GGA string from the GPS, and
  // check if it's a valid fix, and extract the data.
  getNMEA("$GPGGA");    
  delay(100);
  numSats = getSats();
  fixType = getFixType();
  // Make sure we have a valid fix
  if (fixType != 0) {
    getTime(time);
    latitude = getLat();
    longitude = getLong();
    altitude = getAlt();

    // Keep track of the maximum altitude
  }     

  // Convert latitude and longitude into strings.
  char latString[12]; 
  char longString[12];
  doubleToString(latitude, 4, latString);
  doubleToString(longitude, 4, longString);

  sprintf(buffer, "%02d:%02d:%02d,%s,%s,%ld", 
    time[0], time[1], time[2], latString, longString, altitude);
  Serial.println(buffer);

  if (fixType > 0) {
    if (ExOnce==0){
      digitalWrite(13, HIGH);
      //ExOnce=1;
      sendsms();
      logftp();
      // for (int i=0; i<3; i++) {    // Wait 30 sec for a connection.
      //   delay(10000);                        
      // } 
    }
  }

  delay(200);
}

void sendsms(){ 
  Serial.println("AT+CMGF=1");         // Set the SMS mode to text. 
  delay(500);
  Serial.print("AT+CMGS=");            // Send the SMS the number.
  Serial.print(34,BYTE);               // Send the " char.
  Serial.print("**********");          // Send the number change ********* 
                                       // by the actual number.
  Serial.println(34,BYTE);             // Send the " char.
  delay(1500); 
  Serial.print("Hi this is the General text testing."); // The SMS body
  delay(500);
  Serial.print(0x1A,BYTE);             // End of message command 1A (hex)

  delay(20000);
 }

void logftp(){ 
  Serial.println("AT&k3");         // Flow activate

  delay(1000);
  Serial.print("AT+KCNXCFG=0,");     // Connect to GPRS
  Serial.print(34,BYTE);
  Serial.print("GPRS");
  Serial.print(34,BYTE);
  Serial.print(",");
  Serial.print(34,BYTE);
  //Serial.print("wap.cingular");
  Serial.print("epc.tmobile.com");
  Serial.print(34,BYTE);
  Serial.print(",");
  Serial.print(34,BYTE);
  Serial.print(34,BYTE);
  Serial.print(",");
  Serial.print(34,BYTE);
  Serial.println(34,BYTE);

  delay(1000);
  Serial.println("AT+KCNXTIMER=0,60,2,70");   // Set timers

  delay(1000);
  Serial.println("AT+CGATT=1");               // Network check

  delay(1000);
  Serial.print("AT+KFTPCFG=0,");    //FTP configuration/connect
  Serial.print(34,BYTE);
  Serial.print("ftp.insertaddress.com");  //FTP address
  Serial.print(34,BYTE);
  Serial.print(",");
  Serial.print(34,BYTE);
  Serial.print("username");     //Username
  Serial.print(34,BYTE);
  Serial.print(",");
  Serial.print(34,BYTE);
  Serial.print("password");       //Password
  Serial.print(34,BYTE);
  Serial.println(",21,0");        //Port         

  delay(500);
  Serial.print("AT+KPATTERN=");     
  Serial.print(34,BYTE);
  Serial.print("--EOF--Pattern--");
  Serial.println(34,BYTE);

  delay(500);
  Serial.print("AT+KFTPSND=0,,");
  Serial.print(34,BYTE);
  Serial.print("log");          //Directory folder of FTP
  Serial.print(34,BYTE);
  Serial.print(",");
  Serial.print(34,BYTE);
  Serial.print("pol.txt");      //Text file
  Serial.print(34,BYTE);
  Serial.println(",0");

  delay(12000);       

  Serial.print(buffer);   
  Serial.println("--EOF--Pattern--"); 
  delay(12000);

  Serial.println("AT+KTCPCLOSE=1,1"); 
  delay(1000);
} 

// ------- GPS Parsing ----------

// Reads a line from the GPS NMEA serial output
// Give up after trying to read 1000 bytes (~2 seconds)
int readLine(void) {
  char c;
  byte bufferIndex = 0;
  boolean startLine = 0;
  byte retries = 0;
  while (retries < 20) {
    c = mySerial.read();

    if (c == -1) { 
      delay(2); 
      continue; 
    }

    if (c == '\n') continue;
    if (c == '$') startLine = 1;
    if ((bufferIndex == BUFFERSIZE-1) || (c == '\r')) {
      if (startLine) {
        buffer[bufferIndex] = 0;
        return 1;
      }
    }
    if (startLine)
      buffer[bufferIndex++] = c;
    //} 
    else {
      retries++;
      delay(50);
    }
  }
  return 0;
}

// Returns a specific field from the buffer
void getField(int getId, char *field, int maxLen) {
  byte bufferIndex = 0;
  byte fieldId = 0;
  byte i = 0;
  while (bufferIndex < sizeof(buffer)) {
    if (fieldId == getId) {
      // End of string, or string overflow
      if (buffer[bufferIndex] == ',' || i > (maxLen - 2)) {
        field[i] = 0;   // Null terminate
        return;
      }
      // Buffer chars to field
      field[i++] = buffer[bufferIndex++];
    } 
     else {
      // Advance field on comma
      if (buffer[bufferIndex] == ',') {
        bufferIndex++;          //Advance in  buffer
        fieldId++;              // Increase field     position counter
      } 
      else {
        bufferIndex++;          // Advance in  buffer
      }
    }
  }
  // Null terminate incase we didn't already..
  field[i] = 0;
}

// Polls for an NMEA sentence of type requested
// Validates checksum, silently retries on failed checksums
int getNMEA(char *getType) {
  char type[7];
  byte retries = 0;
  while (retries < 2) {
    if (readLine() && validateChecksum()) {
      ;
      getField(0, type, sizeof(type));
      if (strcmp(type, getType) == 0) {
        return 1;
      }
    } 
    else {
      retries++;
     }
  }
  Serial.println("Failed to read GPS");

  return 0;
}

// Validates the checksum on an NMEA string
// Returns 1 on valid checksum, 0 otherwise
int validateChecksum(void) {
  char gotSum[2];
  gotSum[0] = buffer[strlen(buffer) - 2];
  gotSum[1] = buffer[strlen(buffer) - 1];
  // Check that the checksums match up
  if ((16 * atoh(gotSum[0])) + atoh(gotSum[1]) == getCheckSum(buffer))
    return 1;
  else
    return 0;
}

// Calculates the checksum for a given string
// returns as integer
int getCheckSum(char *string) {
  int i; 
  int XOR;  
  int c;
  // Calculate checksum ignoring any $'s in the string
  for (XOR = 0, i = 0; i < strlen(string); i++) {
    c = (unsigned char)string[i];
    if (c == '*') break;
    if (c != '$') XOR ^= c;
  }
  return XOR;
}

// Returns the groundspeed in km/h
int getSpeed(void) {
  char field[10];
  getField(7, field, sizeof(field));
  int speed = atoi(field);
  return speed;
}

// Return the fix type from a GGA string
int getFixType(void) {
  char field[5];
  getField(6, field, sizeof(field));
  int fixType = atoi(field);
  return fixType;
}

// Return the altitude in meters from a GGA string
long getAlt(void) {
  char field[10];
  getField(9, field, sizeof(field));
  long altitude = atol(field);
  return altitude;
}

// Returns the number of satellites being tracked from a GGA string
int getSats(void) {
  char field[3];
  getField(7, field, sizeof(field));
  int numSats = atoi(field);
  return numSats;
}

// Read the latitude in decimal format from a GGA string
double getLat(void) {
  char field[12];
  getField(2, field, sizeof(field));   // read the latitude
  double latitude = atof(field);       // convert to a  double (precise)
  int deg = (int) latitude / 100;      // extract the number of degrees
  double min = latitude - (100 * deg); // work out the number of minutes
  latitude = deg + (double) min/60.0;  // convert to decimal format
  getField(3, field, sizeof(field));   // get the hemisphere (N/S)

  // sign the decimal latitude correctly
  if (strcmp(field, "S") == 0)
    latitude *= -1;

  return latitude;
}

// Read the longitude in decimal format from a GGA string
double getLong(void) {
  char field[12];
  getField(4, field, sizeof(field));    // read the longitude
  double longitude = atof(field);       // convert to a double
  int deg = (int) longitude / 100;      // extract the number of degrees
  double min = longitude - (100 * deg); // work out the number of minutes
  longitude = deg + (double) min/60.00; // convert to decimal format
  getField(5, field, sizeof(field));    // get the E/W status

  // sign decimal latitude correctly
  if (strcmp(field, "W") == 0) 
    longitude *= -1;

  return longitude;
}

// Converts UTC time to the correct timezone
void convertTime(int *time) {
  // How many hours off GMT are we?
  float offset = -5;
  long sectime = ((long)(time[0]) * 3600) + (time[1] * 60) + time[2];
  sectime += (offset * 3600.0);
  // Did we wrap around?
  if (sectime < 0) sectime += 86400;
  if (sectime > 86400) sectime -= 86400;
  // Convert back to time
  time[0] = (int)(sectime / 3600);
  time[1] = (int)((sectime % 3600) / 60);
  time[2] = (int)((sectime % 3600) % 60);
}

// Parses a time field from a GGA string
void parseTime(char *field, int *time) {
  char tmp[3]; 
  tmp[2] = 0; // Init tmp and null terminate
  tmp[0] = field[0]; 
  tmp[1] = field[1]; 
  time[0] = atoi(tmp); // Hours
  tmp[0] = field[2]; 
  tmp[1] = field[3]; 
  time[1] = atoi(tmp); // Minutes
  tmp[0] = field[4]; 
  tmp[1] = field[5]; 
  time[2] = atoi(tmp); // Seconds
}

// Gets the hours, minutes and seconds from a GGA string
void getTime(int *time) {
  char field[12];
  getField(1, field, sizeof(field));
  parseTime(field, time);
  convertTime(time);
}


// ------ MISC ----------

// Returns a string with a textual representation of a float
void doubleToString(double val, int precision, char *string){

  // Print the int part
  sprintf(string, "%d", (int)(val));
  if(precision > 0) {
    // Print the decimal point
    strcat(string, ".");
    unsigned long frac;
    unsigned long mult = 1;
    int padding = precision -1;
    while (precision--) { 
      mult *=10; 
    }
    if (val >= 0)
      frac = (val - (int)(val)) * mult;
    else
      frac = ((int)(val)- val ) * mult;
    unsigned long frac1 = frac;
    while (frac1 /= 10) { 
      padding--; 
    }
    while (padding--) { 
      strcat(string, "0"); 
    }

    // Convert and print the fraction part
    sprintf(string+strlen(string), "%d", (int)(frac));
  }
}


// Converts a HEX string to an int
int atoh(char c) {
  if (c >= 'A' && c <= 'F')
    return c - 55;
  else if (c >= 'a' && c <= 'f')
    return c - 87;
  else
    return c - 48;
}
1
cut the code down to the part that deals with the file writing and it will make it a lot easier for us to help you find the problem.twain249
sprintf(buffer, "%02d:%02d:%02d,%s,%s,%ld", time[0], time[1], time[2], latString, longString, altitude); Serial.println(buffer); this part of the code prints the gps coordinates and puts it into the buffer as characters which I defined earlier with a max size of 100. Serial.print("pol.txt"); Is where it creates the text file within my server under the log directory.teddywestside
Are there two Arduinos (one Mega and one Uno) and a PC? If so, which is connected to the PC and is it the PC which is writing the file? Also, are you running the same sketch on both Arduinos? If not, which Arduino is the posted sketch running on?Matthew Murdoch
There are 2 arduuinos. The code is for the Mega and the mega is connected to the PC but I will be doing everything wirelessly and by battery power. The uno has an entirely different sketch dealing with a different aspect of the project.teddywestside
The code running on the PC will be controlling the writing of the file. It would help if you posted that code - the Arduino code isn't too relevant.Matthew Murdoch

1 Answers

2
votes

If the server is where the text file is received via SMS/GSM, that server program controls how the file is written or appended. Your posted Arduino code would not need to be changed. On the server, where you now open the file - first check if the file exists and if it does, change the open function to add append mode. Exactly how depends on the OS/language of your server program. But you should be able to figure it out from reading the documentation on the open call.