/ SD_Basic_GPS_Logger / SD_GPSLogger / SD_GPSLogger.ino
SD_GPSLogger.ino
  1  // SPDX-FileCopyrightText: Bill Greiman for Adafruit Industries
  2  //
  3  // SPDX-License-Identifier: MIT
  4  
  5  // Ladyada's logger modified by Bill Greiman to use the SdFat library
  6  
  7  // this is a generic logger that does checksum testing so the data written should be always good
  8  // Assumes a sirf III chipset logger attached to pin 2 and 3
  9  
 10  #include <SD.h>
 11  #include <avr/sleep.h>
 12  #include "GPSconfig.h"
 13  
 14  // If using Arduino IDE prior to 1.0,
 15  // make sure to install newsoftserial from Mikal Hart
 16  // http://arduiniana.org/libraries/NewSoftSerial/
 17  #if ARDUINO >= 100
 18   #include <SoftwareSerial.h>
 19  #else
 20   #include <NewSoftSerial.h>
 21  #endif
 22  
 23  // power saving modes
 24  #define SLEEPDELAY 0    /* power-down time in seconds. Max 65535. Ignored if TURNOFFGPS == 0 */
 25  #define TURNOFFGPS 0    /* set to 1 to enable powerdown of arduino and GPS. Ignored if SLEEPDELAY == 0 */
 26  #define LOG_RMC_FIXONLY 0  /* set to 1 to only log to SD when GPD has a fix */
 27  
 28  // what to log
 29  #define LOG_RMC 1 // RMC-Recommended Minimum Specific GNSS Data, message 103,04
 30  #define LOG_GGA 0 // GGA-Global Positioning System Fixed Data, message 103,00
 31  #define LOG_GLL 0 // GLL-Geographic Position-Latitude/Longitude, message 103,01
 32  #define LOG_GSA 0 // GSA-GNSS DOP and Active Satellites, message 103,02
 33  #define LOG_GSV 0 // GSV-GNSS Satellites in View, message 103,03
 34  #define LOG_VTG 0 // VTG-Course Over Ground and Ground Speed, message 103,05
 35  
 36  // Use pins 2 and 3 to talk to the GPS. 2 is the TX pin, 3 is the RX pin
 37  #if ARDUINO >= 100
 38   SoftwareSerial gpsSerial =  SoftwareSerial(2, 3);
 39  #else
 40   NewSoftSerial gpsSerial =  NewSoftSerial(2, 3);
 41  #endif
 42  // Set the GPSRATE to the baud rate of the GPS module. Most are 4800
 43  // but some are 38400 or other. Check the datasheet!
 44  #define GPSRATE 4800
 45  
 46  // Set the pins used 
 47  #define powerPin 4
 48  #define led1Pin 5
 49  #define led2Pin 6
 50  #define chipSelect 10
 51  
 52  
 53  #define BUFFSIZE 90
 54  char buffer[BUFFSIZE];
 55  uint8_t bufferidx = 0;
 56  bool fix = false; // current fix data
 57  bool gotGPRMC;    //true if current data is a GPRMC strinng
 58  uint8_t i;
 59  File logfile;
 60  
 61  // read a Hex value and return the decimal equivalent
 62  uint8_t parseHex(char c) {
 63    if (c < '0')
 64      return 0;
 65    if (c <= '9')
 66      return c - '0';
 67    if (c < 'A')
 68      return 0;
 69    if (c <= 'F')
 70      return (c - 'A')+10;
 71  }
 72  
 73  // blink out an error code
 74  void error(uint8_t errno) {
 75  /*
 76    if (SD.errorCode()) {
 77      putstring("SD error: ");
 78      Serial.print(card.errorCode(), HEX);
 79      Serial.print(',');
 80      Serial.println(card.errorData(), HEX);
 81    }
 82    */
 83    while(1) {
 84      for (i=0; i<errno; i++) {
 85        digitalWrite(led1Pin, HIGH);
 86        digitalWrite(led2Pin, HIGH);
 87        delay(100);
 88        digitalWrite(led1Pin, LOW);
 89        digitalWrite(led2Pin, LOW);
 90        delay(100);
 91      }
 92      for (; i<10; i++) {
 93        delay(200);
 94      }
 95    }
 96  }
 97  
 98  void setup() {
 99    WDTCSR |= (1 << WDCE) | (1 << WDE);
100    WDTCSR = 0;
101    Serial.begin(9600);
102    Serial.println("\r\nGPSlogger");
103    pinMode(led1Pin, OUTPUT);
104    pinMode(led2Pin, OUTPUT);
105    pinMode(powerPin, OUTPUT);
106    digitalWrite(powerPin, LOW);
107  
108    // make sure that the default chip select pin is set to
109    // output, even if you don't use it:
110    pinMode(10, OUTPUT);
111    
112    // see if the card is present and can be initialized:
113    if (!SD.begin(chipSelect)) {
114      Serial.println("Card init. failed!");
115      error(1);
116    }
117  
118    strcpy(buffer, "GPSLOG00.TXT");
119    for (i = 0; i < 100; i++) {
120      buffer[6] = '0' + i/10;
121      buffer[7] = '0' + i%10;
122      // create if does not exist, do not open existing, write, sync after write
123      if (! SD.exists(buffer)) {
124        break;
125      }
126    }
127  
128    logfile = SD.open(buffer, FILE_WRITE);
129    if( ! logfile ) {
130      Serial.print("Couldnt create "); Serial.println(buffer);
131      error(3);
132    }
133    Serial.print("Writing to "); Serial.println(buffer);
134    
135    // connect to the GPS at the desired rate
136    gpsSerial.begin(GPSRATE);
137    
138    Serial.println("Ready!");
139    
140    gpsSerial.print(SERIAL_SET);
141    delay(250);
142  
143  #if (LOG_DDM == 1)
144       gpsSerial.print(DDM_ON);
145  #else
146       gpsSerial.print(DDM_OFF);
147  #endif
148    delay(250);
149  #if (LOG_GGA == 1)
150      gpsSerial.print(GGA_ON);
151  #else
152      gpsSerial.print(GGA_OFF);
153  #endif
154    delay(250);
155  #if (LOG_GLL == 1)
156      gpsSerial.print(GLL_ON);
157  #else
158      gpsSerial.print(GLL_OFF);
159  #endif
160    delay(250);
161  #if (LOG_GSA == 1)
162      gpsSerial.print(GSA_ON);
163  #else
164      gpsSerial.print(GSA_OFF);
165  #endif
166    delay(250);
167  #if (LOG_GSV == 1)
168      gpsSerial.print(GSV_ON);
169  #else
170      gpsSerial.print(GSV_OFF);
171  #endif
172    delay(250);
173  #if (LOG_RMC == 1)
174      gpsSerial.print(RMC_ON);
175  #else
176      gpsSerial.print(RMC_OFF);
177  #endif
178    delay(250);
179  
180  #if (LOG_VTG == 1)
181      gpsSerial.print(VTG_ON);
182  #else
183      gpsSerial.print(VTG_OFF);
184  #endif
185    delay(250);
186  
187  #if (USE_WAAS == 1)
188      gpsSerial.print(WAAS_ON);
189  #else
190      gpsSerial.print(WAAS_OFF);
191  #endif
192  }
193  
194  void loop() {
195    //Serial.println(Serial.available(), DEC);
196    char c;
197    uint8_t sum;
198  
199    // read one 'line'
200    if (gpsSerial.available()) {
201      c = gpsSerial.read();
202  #if ARDUINO >= 100
203      //Serial.write(c);
204  #else
205      //Serial.print(c, BYTE);
206  #endif
207      if (bufferidx == 0) {
208        while (c != '$')
209          c = gpsSerial.read(); // wait till we get a $
210      }
211      buffer[bufferidx] = c;
212  
213  #if ARDUINO >= 100
214      //Serial.write(c);
215  #else
216      //Serial.print(c, BYTE);
217  #endif
218      if (c == '\n') {
219        //putstring_nl("EOL");
220        //Serial.print(buffer);
221        buffer[bufferidx+1] = 0; // terminate it
222  
223        if (buffer[bufferidx-4] != '*') {
224          // no checksum?
225          Serial.print('*');
226          bufferidx = 0;
227          return;
228        }
229        // get checksum
230        sum = parseHex(buffer[bufferidx-3]) * 16;
231        sum += parseHex(buffer[bufferidx-2]);
232  
233        // check checksum
234        for (i=1; i < (bufferidx-4); i++) {
235          sum ^= buffer[i];
236        }
237        if (sum != 0) {
238          //putstring_nl("Cxsum mismatch");
239          Serial.print('~');
240          bufferidx = 0;
241          return;
242        }
243        // got good data!
244  
245        gotGPRMC = strstr(buffer, "GPRMC");
246        if (gotGPRMC) {
247          // find out if we got a fix
248          char *p = buffer;
249          p = strchr(p, ',')+1;
250          p = strchr(p, ',')+1;       // skip to 3rd item
251          
252          if (p[0] == 'V') {
253            digitalWrite(led1Pin, LOW);
254            fix = false;
255          } else {
256            digitalWrite(led1Pin, HIGH);
257            fix = true;
258          }
259        }
260        if (LOG_RMC_FIXONLY) {
261          if (!fix) {
262            Serial.print('_');
263            bufferidx = 0;
264            return;
265          }
266        }
267        // rad. lets log it!
268        
269        Serial.print(buffer);    //first, write it to the serial monitor
270        Serial.print('#');
271        
272        if (gotGPRMC)      //If we have a GPRMC string
273        {
274          // Bill Greiman - need to write bufferidx + 1 bytes to getCR/LF
275          bufferidx++;
276  
277          digitalWrite(led2Pin, HIGH);      // Turn on LED 2 (indicates write to SD)
278  
279          logfile.write((uint8_t *) buffer, bufferidx);    //write the string to the SD file
280          logfile.flush();
281          /*
282          if( != bufferidx) {
283             putstring_nl("can't write!");
284             error(4);
285          }
286          */
287  
288          digitalWrite(led2Pin, LOW);    //turn off LED2 (write to SD is finished)
289  
290          bufferidx = 0;    //reset buffer pointer
291  
292          if (fix) {  //(don't sleep if there's no fix)
293            
294            if ((TURNOFFGPS) && (SLEEPDELAY)) {      // turn off GPS module? 
295            
296              digitalWrite(powerPin, HIGH);  //turn off GPS
297  
298              delay(100);  //wait for serial monitor write to finish
299              sleep_sec(SLEEPDELAY);  //turn off CPU
300    
301              digitalWrite(powerPin, LOW);  //turn on GPS
302            } //if (TURNOFFGPS) 
303           
304          } //if (fix)
305          
306          return;
307        }//if (gotGPRMC)
308        
309      }
310      bufferidx++;
311      if (bufferidx == BUFFSIZE-1) {
312         Serial.print('!');
313         bufferidx = 0;
314      }
315    } else {
316  
317    }
318  
319  }
320  
321  void sleep_sec(uint16_t x) {
322    while (x--) {
323       // set the WDT to wake us up!
324      WDTCSR |= (1 << WDCE) | (1 << WDE); // enable watchdog & enable changing it
325      WDTCSR = (1<< WDE) | (1 <<WDP2) | (1 << WDP1);
326      WDTCSR |= (1<< WDIE);
327      set_sleep_mode(SLEEP_MODE_PWR_DOWN);
328   //   sleep_enable();
329      sleep_mode();
330  //    sleep_disable();
331    }
332  }
333  
334  SIGNAL(WDT_vect) {
335    WDTCSR |= (1 << WDCE) | (1 << WDE);
336    WDTCSR = 0;
337  }
338  
339  /* End code */