/* Code starts here - call it GPSLogger_v2.1 :) */
// this is a generic logger that does checksum testing so the data written should be always good
// Assumes a sirf III chipset logger attached to pin 0 and 1
#include "AF_SDLog.h"
#include "util.h"
#include <avr/pgmspace.h>
#include <avr/sleep.h>
// power saving modes
#define SLEEPDELAY 0
#define TURNOFFGPS 0
#define LOG_RMC_FIXONLY 1
AF_SDLog card;
File f;
#define led1Pin 4
#define led2Pin 3
#define powerPin 2
#define BUFFSIZE 75
char buffer[BUFFSIZE];
uint8_t bufferidx = 0;
uint8_t fix = 0; // current fix data
uint8_t i;
/* EXAMPLE
$PSRF103,<msg>,<mode>,<rate>,<cksumEnable>*CKSUM<CR><LF>
<msg> 00=GGA,01=GLL,02=GSA,03=GSV,04=RMC,05=VTG
<mode> 00=SetRate,01=Query
<rate> Output every <rate>seconds, off=00,max=255
<cksumEnable> 00=disable Checksum,01=Enable checksum for specified message
Note: checksum is required
Example 1: Query the GGA message with checksum enabled
$PSRF103,00,01,00,01*25
Example 2: Enable VTG message for a 1Hz constant output with checksum enabled
$PSRF103,05,00,01,01*20
Example 3: Disable VTG message
$PSRF103,05,00,00,01*21
*/
#define SERIAL_SET "$PSRF100,01,4800,08,01,00*0E\r\n"
// GGA-Global Positioning System Fixed Data, message 103,00
#define LOG_GGA 0
#define GGA_ON "$PSRF103,00,00,01,01*25\r\n"
#define GGA_OFF "$PSRF103,00,00,00,01*24\r\n"
// GLL-Geographic Position-Latitude/Longitude, message 103,01
#define LOG_GLL 0
#define GLL_ON "$PSRF103,01,00,01,01*26\r\n"
#define GLL_OFF "$PSRF103,01,00,00,01*27\r\n"
// GSA-GNSS DOP and Active Satellites, message 103,02
#define LOG_GSA 0
#define GSA_ON "$PSRF103,02,00,01,01*27\r\n"
#define GSA_OFF "$PSRF103,02,00,00,01*26\r\n"
// GSV-GNSS Satellites in View, message 103,03
#define LOG_GSV 0
#define GSV_ON "$PSRF103,03,00,01,01*26\r\n"
#define GSV_OFF "$PSRF103,03,00,00,01*27\r\n"
// RMC-Recommended Minimum Specific GNSS Data, message 103,04
#define LOG_RMC 1
#define RMC_ON "$PSRF103,04,00,01,01*21\r\n"
#define RMC_OFF "$PSRF103,04,00,00,01*20\r\n"
// VTG-Course Over Ground and Ground Speed, message 103,05
#define LOG_VTG 0
#define VTG_ON "$PSRF103,05,00,01,01*20\r\n"
#define VTG_OFF "$PSRF103,05,00,00,01*21\r\n"
// Switch Development Data Messages On/Off, message 105
#define LOG_DDM 1
#define DDM_ON "$PSRF105,01*3E\r\n"
#define DDM_OFF "$PSRF105,00*3F\r\n"
#define USE_WAAS 0 // useful in US, but slower fix
#define WAAS_ON "$PSRF151,01*3F\r\n" // the command for turning on WAAS
#define WAAS_OFF "$PSRF151,00*3E\r\n" // the command for turning off WAAS
// read a Hex value and return the decimal equivalent
uint8_t parseHex(char c) {
if (c < '0')
return 0;
if (c <= '9')
return c - '0';
if (c < 'A')
return 0;
if (c <= 'F')
return (c - 'A')+10;
}
// blink out an error code
void error(uint8_t errno) {
while(1) {
for (i=0; i<errno; i++) {
digitalWrite(led1Pin, HIGH);
digitalWrite(led2Pin, HIGH);
delay(100);
digitalWrite(led1Pin, LOW);
digitalWrite(led2Pin, LOW);
delay(100);
}
for (; i<10; i++) {
delay(200);
}
}
}
void setup()
{
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0;
Serial.begin(4800);
putstring_nl("\r\nGPSlogger");
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(powerPin, OUTPUT);
digitalWrite(powerPin, LOW);
if (!card.init_card()) {
putstring_nl("Card init. failed!");
error(1);
}
if (!card.open_partition()) {
putstring_nl("No partition!");
error(2);
}
if (!card.open_filesys()) {
putstring_nl("Can't open filesys");
error(3);
}
if (!card.open_dir("/")) {
putstring_nl("Can't open /");
error(4);
}
strcpy(buffer, "GPSLOG00.TXT");
for (buffer[6] = '0'; buffer[6] <= '9'; buffer[6]++) {
for (buffer[7] = '0'; buffer[7] <= '9'; buffer[7]++) {
//putstring("\ntrying to open ");Serial.println(buffer);
f = card.open_file(buffer);
if (!f)
break;
card.close_file(f);
}
if (!f)
break;
}
if(!card.create_file(buffer)) {
putstring("couldnt create ");
Serial.println(buffer);
error(5);
}
f = card.open_file(buffer);
if (!f) {
putstring("error opening ");
Serial.println(buffer);
card.close_file(f);
error(6);
}
putstring("writing to ");
Serial.println(buffer);
putstring_nl("ready!");
putstring(SERIAL_SET);
delay(250);
if (LOG_DDM)
putstring(DDM_ON);
else
putstring(DDM_OFF);
delay(250);
if (LOG_GGA)
putstring(GGA_ON);
else
putstring(GGA_OFF);
delay(250);
if (LOG_GLL)
putstring(GLL_ON);
else
putstring(GLL_OFF);
delay(250);
if (LOG_GSA)
putstring(GSA_ON);
else
putstring(GSA_OFF);
delay(250);
if (LOG_GSV)
putstring(GSV_ON);
else
putstring(GSV_OFF);
delay(250);
if (LOG_RMC)
putstring(RMC_ON);
else
putstring(RMC_OFF);
delay(250);
if (LOG_VTG)
putstring(VTG_ON);
else
putstring(VTG_OFF);
delay(250);
if (USE_WAAS)
putstring(WAAS_ON);
else
putstring(WAAS_OFF);
}
void loop()
{
//Serial.println(Serial.available(), DEC);
char c;
uint8_t sum;
// read one 'line'
if (Serial.available()) {
c = Serial.read();
//Serial.print(c, BYTE);
if (bufferidx == 0) {
while (c != '$')
c = Serial.read(); // wait till we get a $
}
buffer[bufferidx] = c;
//Serial.print(c, BYTE);
if (c == '\n') {
//putstring_nl("EOL");
//Serial.print(buffer);
buffer[bufferidx+1] = 0; // terminate it
if (buffer[bufferidx-4] != '*') {
// no checksum?
Serial.print('*', BYTE);
bufferidx = 0;
return;
}
// get checksum
sum = parseHex(buffer[bufferidx-3]) * 16;
sum += parseHex(buffer[bufferidx-2]);
// check checksum
for (i=1; i < (bufferidx-4); i++) {
sum ^= buffer[i];
}
if (sum != 0) {
//putstring_nl("Cxsum mismatch");
Serial.print('~', BYTE);
bufferidx = 0;
return;
}
// got good data!
if (strstr(buffer, "GPRMC")) {
// find out if we got a fix
char *p = buffer;
p = strchr(p, ',')+1;
p = strchr(p, ',')+1; // skip to 3rd item
if (p[0] == 'V') {
digitalWrite(led1Pin, LOW);
fix = 0;
} else {
digitalWrite(led1Pin, HIGH);
fix = 1;
}
}
if (LOG_RMC_FIXONLY) {
if (!fix) {
Serial.print('_', BYTE);
bufferidx = 0;
return;
}
}
// rad. lets log it!
Serial.print(buffer);
Serial.print('#', BYTE);
digitalWrite(led2Pin, HIGH); // sets the digital pin as output
if(card.write_file(f, (uint8_t *) buffer, bufferidx) != bufferidx) {
putstring_nl("can't write!");
return;
}
digitalWrite(led2Pin, LOW);
bufferidx = 0;
// turn off GPS module?
if (TURNOFFGPS) {
digitalWrite(powerPin, HIGH);
}
sleep_sec(SLEEPDELAY);
digitalWrite(powerPin, LOW);
return;
}
bufferidx++;
if (bufferidx == BUFFSIZE-1) {
Serial.print('!', BYTE);
bufferidx = 0;
}
} else {
}
}
void sleep_sec(uint8_t x) {
while (x--) {
// set the WDT to wake us up!
WDTCSR |= (1 << WDCE) | (1 << WDE); // enable watchdog & enable changing it
WDTCSR = (1<< WDE) | (1 <<WDP2) | (1 << WDP1);
WDTCSR |= (1<< WDIE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
}
}
SIGNAL(WDT_vect) {
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0;
}
/* End code */