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