This version is the one to be submitted as a part the Hackster.io contest, Unleash Invisible Intelligence

Committer:
gov1
Date:
Tue Jul 31 16:30:32 2018 +0000
Revision:
0:a761fba7f8a8
complete version with emer. batt low check

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gov1 0:a761fba7f8a8 1 /***********************************
gov1 0:a761fba7f8a8 2 This is our GPS library
gov1 0:a761fba7f8a8 3
gov1 0:a761fba7f8a8 4 Adafruit invests time and resources providing this open source code,
gov1 0:a761fba7f8a8 5 please support Adafruit and open-source hardware by purchasing
gov1 0:a761fba7f8a8 6 products from Adafruit!
gov1 0:a761fba7f8a8 7
gov1 0:a761fba7f8a8 8 Written by Limor Fried/Ladyada for Adafruit Industries.
gov1 0:a761fba7f8a8 9 BSD license, check license.txt for more information
gov1 0:a761fba7f8a8 10 All text above must be included in any redistribution
gov1 0:a761fba7f8a8 11 ****************************************/
gov1 0:a761fba7f8a8 12
gov1 0:a761fba7f8a8 13 #include "MBed_Adafruit_GPS.h"
gov1 0:a761fba7f8a8 14
gov1 0:a761fba7f8a8 15 // how long are max NMEA lines to parse?
gov1 0:a761fba7f8a8 16 #define MAXLINELENGTH 120
gov1 0:a761fba7f8a8 17
gov1 0:a761fba7f8a8 18 // we double buffer: read one line in and leave one for the main program
gov1 0:a761fba7f8a8 19 volatile char line1[MAXLINELENGTH];
gov1 0:a761fba7f8a8 20 volatile char line2[MAXLINELENGTH];
gov1 0:a761fba7f8a8 21 // our index into filling the current line
gov1 0:a761fba7f8a8 22 volatile uint16_t lineidx=0;
gov1 0:a761fba7f8a8 23 // pointers to the double buffers
gov1 0:a761fba7f8a8 24 volatile char *currentline;
gov1 0:a761fba7f8a8 25 volatile char *lastline;
gov1 0:a761fba7f8a8 26 volatile bool recvdflag;
gov1 0:a761fba7f8a8 27 volatile bool inStandbyMode;
gov1 0:a761fba7f8a8 28
gov1 0:a761fba7f8a8 29
gov1 0:a761fba7f8a8 30 bool Adafruit_GPS::parse(char *nmea) {
gov1 0:a761fba7f8a8 31 // do checksum check
gov1 0:a761fba7f8a8 32
gov1 0:a761fba7f8a8 33 // first look if we even have one
gov1 0:a761fba7f8a8 34 if (nmea[strlen(nmea)-4] == '*') {
gov1 0:a761fba7f8a8 35 uint16_t sum = parseHex(nmea[strlen(nmea)-3]) * 16;
gov1 0:a761fba7f8a8 36 sum += parseHex(nmea[strlen(nmea)-2]);
gov1 0:a761fba7f8a8 37
gov1 0:a761fba7f8a8 38 // check checksum
gov1 0:a761fba7f8a8 39 for (uint8_t i=1; i < (strlen(nmea)-4); i++) {
gov1 0:a761fba7f8a8 40 sum ^= nmea[i];
gov1 0:a761fba7f8a8 41 }
gov1 0:a761fba7f8a8 42 if (sum != 0) {
gov1 0:a761fba7f8a8 43 // bad checksum :(
gov1 0:a761fba7f8a8 44 //return false;
gov1 0:a761fba7f8a8 45 }
gov1 0:a761fba7f8a8 46 }
gov1 0:a761fba7f8a8 47
gov1 0:a761fba7f8a8 48 // look for a few common sentences
gov1 0:a761fba7f8a8 49 if (strstr(nmea, "$GPGGA")) {
gov1 0:a761fba7f8a8 50 // found GGA
gov1 0:a761fba7f8a8 51 char *p = nmea;
gov1 0:a761fba7f8a8 52 // get time
gov1 0:a761fba7f8a8 53 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 54 float timef = atof(p);
gov1 0:a761fba7f8a8 55 uint32_t time = timef;
gov1 0:a761fba7f8a8 56 hour = time / 10000;
gov1 0:a761fba7f8a8 57 minute = (time % 10000) / 100;
gov1 0:a761fba7f8a8 58 seconds = (time % 100);
gov1 0:a761fba7f8a8 59
gov1 0:a761fba7f8a8 60 milliseconds = fmod((double) timef, 1.0) * 1000;
gov1 0:a761fba7f8a8 61
gov1 0:a761fba7f8a8 62 // parse out latitude
gov1 0:a761fba7f8a8 63 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 64 latitude = atof(p);
gov1 0:a761fba7f8a8 65
gov1 0:a761fba7f8a8 66 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 67 if (p[0] == 'N') lat = 'N';
gov1 0:a761fba7f8a8 68 else if (p[0] == 'S') lat = 'S';
gov1 0:a761fba7f8a8 69 else if (p[0] == ',') lat = 0;
gov1 0:a761fba7f8a8 70 else return false;
gov1 0:a761fba7f8a8 71
gov1 0:a761fba7f8a8 72 // parse out longitude
gov1 0:a761fba7f8a8 73 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 74 longitude = atof(p);
gov1 0:a761fba7f8a8 75
gov1 0:a761fba7f8a8 76 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 77 if (p[0] == 'W') lon = 'W';
gov1 0:a761fba7f8a8 78 else if (p[0] == 'E') lon = 'E';
gov1 0:a761fba7f8a8 79 else if (p[0] == ',') lon = 0;
gov1 0:a761fba7f8a8 80 else return false;
gov1 0:a761fba7f8a8 81
gov1 0:a761fba7f8a8 82 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 83 fixquality = atoi(p);
gov1 0:a761fba7f8a8 84
gov1 0:a761fba7f8a8 85 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 86 satellites = atoi(p);
gov1 0:a761fba7f8a8 87
gov1 0:a761fba7f8a8 88 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 89 HDOP = atof(p);
gov1 0:a761fba7f8a8 90
gov1 0:a761fba7f8a8 91 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 92 altitude = atof(p);
gov1 0:a761fba7f8a8 93 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 94 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 95 geoidheight = atof(p);
gov1 0:a761fba7f8a8 96 return true;
gov1 0:a761fba7f8a8 97 }
gov1 0:a761fba7f8a8 98 if (strstr(nmea, "$GPRMC")) {
gov1 0:a761fba7f8a8 99 // found RMC
gov1 0:a761fba7f8a8 100 char *p = nmea;
gov1 0:a761fba7f8a8 101
gov1 0:a761fba7f8a8 102 // get time
gov1 0:a761fba7f8a8 103 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 104 float timef = atof(p);
gov1 0:a761fba7f8a8 105 uint32_t time = timef;
gov1 0:a761fba7f8a8 106 hour = time / 10000;
gov1 0:a761fba7f8a8 107 minute = (time % 10000) / 100;
gov1 0:a761fba7f8a8 108 seconds = (time % 100);
gov1 0:a761fba7f8a8 109
gov1 0:a761fba7f8a8 110 milliseconds = fmod((double) timef, 1.0) * 1000;
gov1 0:a761fba7f8a8 111
gov1 0:a761fba7f8a8 112 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 113 // Serial.println(p);
gov1 0:a761fba7f8a8 114 if (p[0] == 'A')
gov1 0:a761fba7f8a8 115 fix = true;
gov1 0:a761fba7f8a8 116 else if (p[0] == 'V')
gov1 0:a761fba7f8a8 117 fix = false;
gov1 0:a761fba7f8a8 118 else
gov1 0:a761fba7f8a8 119 return false;
gov1 0:a761fba7f8a8 120
gov1 0:a761fba7f8a8 121 // parse out latitude
gov1 0:a761fba7f8a8 122 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 123 latitude = atof(p);
gov1 0:a761fba7f8a8 124
gov1 0:a761fba7f8a8 125 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 126 if (p[0] == 'N') lat = 'N';
gov1 0:a761fba7f8a8 127 else if (p[0] == 'S') lat = 'S';
gov1 0:a761fba7f8a8 128 else if (p[0] == ',') lat = 0;
gov1 0:a761fba7f8a8 129 else return false;
gov1 0:a761fba7f8a8 130
gov1 0:a761fba7f8a8 131 // parse out longitude
gov1 0:a761fba7f8a8 132 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 133 longitude = atof(p);
gov1 0:a761fba7f8a8 134
gov1 0:a761fba7f8a8 135 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 136 if (p[0] == 'W') lon = 'W';
gov1 0:a761fba7f8a8 137 else if (p[0] == 'E') lon = 'E';
gov1 0:a761fba7f8a8 138 else if (p[0] == ',') lon = 0;
gov1 0:a761fba7f8a8 139 else return false;
gov1 0:a761fba7f8a8 140
gov1 0:a761fba7f8a8 141 // speed
gov1 0:a761fba7f8a8 142 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 143 speed = atof(p);
gov1 0:a761fba7f8a8 144
gov1 0:a761fba7f8a8 145 // angle
gov1 0:a761fba7f8a8 146 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 147 angle = atof(p);
gov1 0:a761fba7f8a8 148
gov1 0:a761fba7f8a8 149 p = strchr(p, ',')+1;
gov1 0:a761fba7f8a8 150 uint32_t fulldate = atof(p);
gov1 0:a761fba7f8a8 151 day = fulldate / 10000;
gov1 0:a761fba7f8a8 152 month = (fulldate % 10000) / 100;
gov1 0:a761fba7f8a8 153 year = (fulldate % 100);
gov1 0:a761fba7f8a8 154
gov1 0:a761fba7f8a8 155 // we dont parse the remaining, yet!
gov1 0:a761fba7f8a8 156 return true;
gov1 0:a761fba7f8a8 157 }
gov1 0:a761fba7f8a8 158
gov1 0:a761fba7f8a8 159 return false;
gov1 0:a761fba7f8a8 160 }
gov1 0:a761fba7f8a8 161
gov1 0:a761fba7f8a8 162 char Adafruit_GPS::read(void) {
gov1 0:a761fba7f8a8 163 char c = 0;
gov1 0:a761fba7f8a8 164
gov1 0:a761fba7f8a8 165 if (paused) return c;
gov1 0:a761fba7f8a8 166
gov1 0:a761fba7f8a8 167 if(!gpsSerial->readable()) return c;
gov1 0:a761fba7f8a8 168 c = gpsSerial->getc();
gov1 0:a761fba7f8a8 169
gov1 0:a761fba7f8a8 170 //Serial.print(c);
gov1 0:a761fba7f8a8 171
gov1 0:a761fba7f8a8 172 if (c == '$') {
gov1 0:a761fba7f8a8 173 currentline[lineidx] = 0;
gov1 0:a761fba7f8a8 174 lineidx = 0;
gov1 0:a761fba7f8a8 175 }
gov1 0:a761fba7f8a8 176 if (c == '\n') {
gov1 0:a761fba7f8a8 177 currentline[lineidx] = 0;
gov1 0:a761fba7f8a8 178
gov1 0:a761fba7f8a8 179 if (currentline == line1) {
gov1 0:a761fba7f8a8 180 currentline = line2;
gov1 0:a761fba7f8a8 181 lastline = line1;
gov1 0:a761fba7f8a8 182 } else {
gov1 0:a761fba7f8a8 183 currentline = line1;
gov1 0:a761fba7f8a8 184 lastline = line2;
gov1 0:a761fba7f8a8 185 }
gov1 0:a761fba7f8a8 186
gov1 0:a761fba7f8a8 187 lineidx = 0;
gov1 0:a761fba7f8a8 188 recvdflag = true;
gov1 0:a761fba7f8a8 189 }
gov1 0:a761fba7f8a8 190
gov1 0:a761fba7f8a8 191 currentline[lineidx++] = c;
gov1 0:a761fba7f8a8 192 if (lineidx >= MAXLINELENGTH)
gov1 0:a761fba7f8a8 193 lineidx = MAXLINELENGTH-1;
gov1 0:a761fba7f8a8 194
gov1 0:a761fba7f8a8 195 return c;
gov1 0:a761fba7f8a8 196 }
gov1 0:a761fba7f8a8 197
gov1 0:a761fba7f8a8 198 Adafruit_GPS::Adafruit_GPS (Serial *ser)
gov1 0:a761fba7f8a8 199 {
gov1 0:a761fba7f8a8 200 common_init(); // Set everything to common state, then...
gov1 0:a761fba7f8a8 201 gpsSerial = ser; // ...override gpsSwSerial with value passed.
gov1 0:a761fba7f8a8 202 }
gov1 0:a761fba7f8a8 203
gov1 0:a761fba7f8a8 204 // Initialization code used by all constructor types
gov1 0:a761fba7f8a8 205 void Adafruit_GPS::common_init(void) {
gov1 0:a761fba7f8a8 206 gpsSerial = NULL;
gov1 0:a761fba7f8a8 207 recvdflag = false;
gov1 0:a761fba7f8a8 208 paused = false;
gov1 0:a761fba7f8a8 209 lineidx = 0;
gov1 0:a761fba7f8a8 210 currentline = line1;
gov1 0:a761fba7f8a8 211 lastline = line2;
gov1 0:a761fba7f8a8 212
gov1 0:a761fba7f8a8 213 hour = minute = seconds = year = month = day =
gov1 0:a761fba7f8a8 214 fixquality = satellites = 0; // uint8_t
gov1 0:a761fba7f8a8 215 lat = lon = mag = 0; // char
gov1 0:a761fba7f8a8 216 fix = false; // bool
gov1 0:a761fba7f8a8 217 milliseconds = 0; // uint16_t
gov1 0:a761fba7f8a8 218 latitude = longitude = geoidheight = altitude =
gov1 0:a761fba7f8a8 219 speed = angle = magvariation = HDOP = 0.0; // float
gov1 0:a761fba7f8a8 220 }
gov1 0:a761fba7f8a8 221
gov1 0:a761fba7f8a8 222 void Adafruit_GPS::begin(int baud)
gov1 0:a761fba7f8a8 223 {
gov1 0:a761fba7f8a8 224 gpsSerial->baud(baud);
gov1 0:a761fba7f8a8 225 wait_ms(10);
gov1 0:a761fba7f8a8 226 }
gov1 0:a761fba7f8a8 227
gov1 0:a761fba7f8a8 228 void Adafruit_GPS::sendCommand(char *str) {
gov1 0:a761fba7f8a8 229 gpsSerial->printf("%s",str);
gov1 0:a761fba7f8a8 230 }
gov1 0:a761fba7f8a8 231
gov1 0:a761fba7f8a8 232 bool Adafruit_GPS::newNMEAreceived(void) {
gov1 0:a761fba7f8a8 233 return recvdflag;
gov1 0:a761fba7f8a8 234 }
gov1 0:a761fba7f8a8 235
gov1 0:a761fba7f8a8 236 void Adafruit_GPS::pause(bool p) {
gov1 0:a761fba7f8a8 237 paused = p;
gov1 0:a761fba7f8a8 238 }
gov1 0:a761fba7f8a8 239
gov1 0:a761fba7f8a8 240 char *Adafruit_GPS::lastNMEA(void) {
gov1 0:a761fba7f8a8 241 recvdflag = false;
gov1 0:a761fba7f8a8 242 return (char *)lastline;
gov1 0:a761fba7f8a8 243 }
gov1 0:a761fba7f8a8 244
gov1 0:a761fba7f8a8 245 // read a Hex value and return the decimal equivalent
gov1 0:a761fba7f8a8 246 uint8_t Adafruit_GPS::parseHex(char c) {
gov1 0:a761fba7f8a8 247 if (c < '0')
gov1 0:a761fba7f8a8 248 return 0;
gov1 0:a761fba7f8a8 249 if (c <= '9')
gov1 0:a761fba7f8a8 250 return c - '0';
gov1 0:a761fba7f8a8 251 if (c < 'A')
gov1 0:a761fba7f8a8 252 return 0;
gov1 0:a761fba7f8a8 253 if (c <= 'F')
gov1 0:a761fba7f8a8 254 return (c - 'A')+10;
gov1 0:a761fba7f8a8 255 }
gov1 0:a761fba7f8a8 256
gov1 0:a761fba7f8a8 257 bool Adafruit_GPS::waitForSentence(char *wait4me, uint8_t max) {
gov1 0:a761fba7f8a8 258 char str[20];
gov1 0:a761fba7f8a8 259
gov1 0:a761fba7f8a8 260 uint8_t i=0;
gov1 0:a761fba7f8a8 261 while (i < max) {
gov1 0:a761fba7f8a8 262 if (newNMEAreceived()) {
gov1 0:a761fba7f8a8 263 char *nmea = lastNMEA();
gov1 0:a761fba7f8a8 264 strncpy(str, nmea, 20);
gov1 0:a761fba7f8a8 265 str[19] = 0;
gov1 0:a761fba7f8a8 266 i++;
gov1 0:a761fba7f8a8 267
gov1 0:a761fba7f8a8 268 if (strstr(str, wait4me))
gov1 0:a761fba7f8a8 269 return true;
gov1 0:a761fba7f8a8 270 }
gov1 0:a761fba7f8a8 271 }
gov1 0:a761fba7f8a8 272
gov1 0:a761fba7f8a8 273 return false;
gov1 0:a761fba7f8a8 274 }
gov1 0:a761fba7f8a8 275
gov1 0:a761fba7f8a8 276 bool Adafruit_GPS::LOCUS_StartLogger(void) {
gov1 0:a761fba7f8a8 277 sendCommand(PMTK_LOCUS_STARTLOG);
gov1 0:a761fba7f8a8 278 recvdflag = false;
gov1 0:a761fba7f8a8 279 return waitForSentence(PMTK_LOCUS_LOGSTARTED);
gov1 0:a761fba7f8a8 280 }
gov1 0:a761fba7f8a8 281
gov1 0:a761fba7f8a8 282 bool Adafruit_GPS::LOCUS_ReadStatus(void) {
gov1 0:a761fba7f8a8 283 sendCommand(PMTK_LOCUS_QUERY_STATUS);
gov1 0:a761fba7f8a8 284
gov1 0:a761fba7f8a8 285 if (! waitForSentence("$PMTKLOG"))
gov1 0:a761fba7f8a8 286 return false;
gov1 0:a761fba7f8a8 287
gov1 0:a761fba7f8a8 288 char *response = lastNMEA();
gov1 0:a761fba7f8a8 289 uint16_t parsed[10];
gov1 0:a761fba7f8a8 290 uint8_t i;
gov1 0:a761fba7f8a8 291
gov1 0:a761fba7f8a8 292 for (i=0; i<10; i++) parsed[i] = -1;
gov1 0:a761fba7f8a8 293
gov1 0:a761fba7f8a8 294 response = strchr(response, ',');
gov1 0:a761fba7f8a8 295 for (i=0; i<10; i++) {
gov1 0:a761fba7f8a8 296 if (!response || (response[0] == 0) || (response[0] == '*'))
gov1 0:a761fba7f8a8 297 break;
gov1 0:a761fba7f8a8 298 response++;
gov1 0:a761fba7f8a8 299 parsed[i]=0;
gov1 0:a761fba7f8a8 300 while ((response[0] != ',') &&
gov1 0:a761fba7f8a8 301 (response[0] != '*') && (response[0] != 0)) {
gov1 0:a761fba7f8a8 302 parsed[i] *= 10;
gov1 0:a761fba7f8a8 303 char c = response[0];
gov1 0:a761fba7f8a8 304 if (isdigit(c))
gov1 0:a761fba7f8a8 305 parsed[i] += c - '0';
gov1 0:a761fba7f8a8 306 else
gov1 0:a761fba7f8a8 307 parsed[i] = c;
gov1 0:a761fba7f8a8 308 response++;
gov1 0:a761fba7f8a8 309 }
gov1 0:a761fba7f8a8 310 }
gov1 0:a761fba7f8a8 311 LOCUS_serial = parsed[0];
gov1 0:a761fba7f8a8 312 LOCUS_type = parsed[1];
gov1 0:a761fba7f8a8 313 if (isalpha(parsed[2])) {
gov1 0:a761fba7f8a8 314 parsed[2] = parsed[2] - 'a' + 10;
gov1 0:a761fba7f8a8 315 }
gov1 0:a761fba7f8a8 316 LOCUS_mode = parsed[2];
gov1 0:a761fba7f8a8 317 LOCUS_config = parsed[3];
gov1 0:a761fba7f8a8 318 LOCUS_interval = parsed[4];
gov1 0:a761fba7f8a8 319 LOCUS_distance = parsed[5];
gov1 0:a761fba7f8a8 320 LOCUS_speed = parsed[6];
gov1 0:a761fba7f8a8 321 LOCUS_status = !parsed[7];
gov1 0:a761fba7f8a8 322 LOCUS_records = parsed[8];
gov1 0:a761fba7f8a8 323 LOCUS_percent = parsed[9];
gov1 0:a761fba7f8a8 324
gov1 0:a761fba7f8a8 325 return true;
gov1 0:a761fba7f8a8 326 }
gov1 0:a761fba7f8a8 327
gov1 0:a761fba7f8a8 328 // Standby Mode Switches
gov1 0:a761fba7f8a8 329 bool Adafruit_GPS::standby(void) {
gov1 0:a761fba7f8a8 330 if (inStandbyMode) {
gov1 0:a761fba7f8a8 331 return false; // Returns false if already in standby mode, so that you do not wake it up by sending commands to GPS
gov1 0:a761fba7f8a8 332 }
gov1 0:a761fba7f8a8 333 else {
gov1 0:a761fba7f8a8 334 inStandbyMode = true;
gov1 0:a761fba7f8a8 335 sendCommand(PMTK_STANDBY);
gov1 0:a761fba7f8a8 336 //return waitForSentence(PMTK_STANDBY_SUCCESS); // don't seem to be fast enough to catch the message, or something else just is not working
gov1 0:a761fba7f8a8 337 return true;
gov1 0:a761fba7f8a8 338 }
gov1 0:a761fba7f8a8 339 }
gov1 0:a761fba7f8a8 340
gov1 0:a761fba7f8a8 341 bool Adafruit_GPS::wakeup(void) {
gov1 0:a761fba7f8a8 342 if (inStandbyMode) {
gov1 0:a761fba7f8a8 343 inStandbyMode = false;
gov1 0:a761fba7f8a8 344 sendCommand(""); // send byte to wake it up
gov1 0:a761fba7f8a8 345 return waitForSentence(PMTK_AWAKE);
gov1 0:a761fba7f8a8 346 }
gov1 0:a761fba7f8a8 347 else {
gov1 0:a761fba7f8a8 348 return false; // Returns false if not in standby mode, nothing to wakeup
gov1 0:a761fba7f8a8 349 }
gov1 0:a761fba7f8a8 350 }