-
Notifications
You must be signed in to change notification settings - Fork 0
/
dGPS.cpp
393 lines (341 loc) · 14.3 KB
/
dGPS.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
//change softrxPin from 10 to 11
// dGPS.cpp
// For use with the Dexter Industries / diCircuits.com dGPS
// The dGPS can be found here: http://dexterindustries.com/Arduino-GPS_Shield.html
#include "dGPS.h"
#include "SoftwareSerial.h"
#include "pins_arduino.h"
//#include "WProgram.h"
#include "Arduino.h"
#include "math.h"
#define MAX_STRING_LEN 300
#define SoftrxPin 11
#define SofttxPin 4
//#define SoftrxPin 33
//#define SofttxPin 31
long fTime; // UTC Time
char *cStatus; // Status
float fLat; // Current Latitude
float fLon; // Current Longitude
float fVel; // Velocity
float fHead; // Heading
long lDate; // UTC Date
float fdist; // Distance to destination
float fazimuth; // Azimuth of destination from current position
char *mode; // Mode
char *checkSum; // Received Checksum
int fSat; // Number of Satellites in use
float hDop; // HDOP
float fAlt; // Altitude above sea level
int computedSum; // Calculated Checksum
SoftwareSerial gpsSerial = SoftwareSerial(SoftrxPin, SofttxPin);
dGPS::dGPS()
{
cont = 0;
bien = 0;
conta = 0;
comandoGPR[0] = '$';
comandoGPR[1] = 'G';
comandoGPR[2] = 'P';
comandoGPR[3] = 'R';
comandoGPR[4] = 'M';
comandoGPR[5] = 'C';
}
void dGPS::init(){
gpsSerial.begin(9600); //start serial for communication with GPS
memset(linea, ' ', sizeof(linea)); }
long dGPS::Time(){ // returns UTC Time
return fTime; }
char *dGPS::Status(){ // returns Status
return cStatus; }
float dGPS::Lat(){ // returns Current Latitude
return fLat; }
float dGPS::Lon(){ // returns Current Longitude
return fLon; }
float dGPS::Vel(){ // returns Velocity
return fVel; }
float dGPS::Head(){ // returns Heading
return fHead; }
long dGPS::Date(){ // returns UTC Date
return lDate; }
float dGPS::Dist(){ // returns Distance to destination
return fdist; }
float dGPS::Azim(){ // returns Azimuth to destination
return fazimuth; }
char *dGPS::Mode(){ // returns Mode
return mode; }
char *dGPS::Checks(){ // returns Received Checksum
return checkSum; }
long int dGPS::Checked(){
return computedSum;
}
// Compare the received checksum, and the calculated checksum.
//If they are completely equal, return true. Otherwise return false.
boolean dGPS::Compare(){
char s[3];
char *recCheck=Checks(); // received checksum
long int x= Checked(); // Computed checksum from the incoming $GPRMC string
char *ccomCheck=itoa(x,s,16); // convert long int to hexadecimal string
char comCheck[strlen(ccomCheck)];
for (int i=0;i<=strlen(ccomCheck);i++){ // convert ToUpper case, each character of hexadecimal string
comCheck[i]= toupper(ccomCheck[i]);}
boolean flag;
// for each character in hexadecimal string, check if it matches with the received checksum value
for (int i=0;i<min(strlen(recCheck),strlen(comCheck));i++){
if (recCheck[i]==comCheck[i])
{ flag=true; } // if characters in checksum match
else { flag=false; } // if characters in checksum do not match
}
return flag; // if all the characters in checksum match, then 'true' is returned. Otherwise, 'false' is returned.
}
int dGPS::SatView(){ // returns Number of Satellites in use
return fSat; }
float dGPS::Hdop(){ // returns HDOP value
return hDop; }
float dGPS::Alti(){ // returns Altitude above sea level
return fAlt; }
// function to read the Y or N character from the user via serial monitor box
void dGPS::getflag(char *str) {
/* The following statements must precede the call to this function,
to clear out any character data already in the serial buffer.
Code: char flag[2];
*flag = Serial.read();
memset(flag, 0, sizeof(flag));
Call: object.getflag(flag); */
while (Serial.available()==0){;} // If nothing available in serial buffer, wait and do nothing.
int index=0;
if (Serial.available()>0){ // If data available in serial buffer, then read it
if (index<2){
str[index]=Serial.read();
index++; }
else str[index]='\0';
delay(5);
}
}
// function to get the latitudinal and longitudinal coordinates of the destination from user
float dGPS::getdestcoord(){
float result;
while (Serial.available()==0) {;} // do nothing until something comes into the serial buffer
if (Serial.available()>0){
result=Serial.parseFloat(); //read a float value from serial monitor box, upto 2 decimal places
delay(5);
}
return result;
}
// update all the fields from the incoming $GPRMC string
boolean dGPS::update(float desLat, float desLon){
//Serial.println("Entered update"); //I added this
while(true){
int byteGPS=-1;
byteGPS=gpsSerial.read(); //read a byte from the serial port
if (byteGPS == -1) { // See if the port is empty yet
delay(5);
}
else {
linea[conta]=byteGPS; // If there is serial port data, it is put in the buffer
conta++;
if (byteGPS==13){ // If the received byte is = to 13, end of transmission
cont=0;
bien=0;
for (int i=1;i<7;i++){ // Verifies if the received command starts with $GPR
if (linea[i]==comandoGPR[i-1]){
bien++;
}
}
if(bien==6){ // If yes, continue and process the data
Serial.print(""); // For some reason, this needs to be here or you won't populate variables. If anyone solves this problem, let us know.
Serial.print("");
Serial.print("-");
//Serial.print("dgps.Update ran"); //I added this
//Serial.println(linea); //Print out the incoming GPRMC string (just for reference)
//I uncommented the line above for testing
//------------------------------------------
// Get Time (UTC)
char *data = "";
memset(data, 0, sizeof(data));
data = dGPS::subStr(linea, ",", 2);
fTime = atol(data);
delay(5);
//------------------------------------------
// Get Status
memset(data, 0, sizeof(data));
cStatus = dGPS::subStr(linea, ",", 3);
delay(5);
//------------------------------------------
// Get Latitude (degrees)
char *hemi;
memset(data, 0, sizeof(data));
char *cLat = "";
cLat = dGPS::subStr(linea, ",", 4);
fLat = strtod(cLat, NULL);
fLat = conv_coords(fLat);
hemi = subStr(linea, ",", 5); // Gets the hemisphere.
if(*hemi == 'S') {fLat = fLat*-1;} // Setting the Latitude.
//Serial.println("Get Lat function ran."); //I added this to test
delay(5);
//------------------------------------------
// Get Longitude (degrees)
memset(data, 0, sizeof(data));
char *cLon = "";
cLon = dGPS::subStr(linea, ",", 6);
fLon = strtod(cLon, NULL);
fLon = conv_coords(fLon);
hemi = subStr(linea, ",", 7); // Gets the hemisphere.
if(*hemi == 'W') {fLon = fLon*-1;} // Setting the Longitude.
//Serial.println("Get Lon function ran."); //I added this to test
delay(5);
//------------------------------------------
// Get Velocity (knots)
memset(data, 0, sizeof(data));
char *cVel = "";
cVel = dGPS::subStr(linea, ",", 8);
fVel = strtod(cVel, NULL);
//Serial.println("Get Vel function ran."); //I added this to test
delay(5);
//------------------------------------------
// Get Heading (degrees)
memset(data, 0, sizeof(data));
char *cHead = "";
cHead = dGPS::subStr(linea, ",", 9);
fHead = strtod(cHead, NULL);
delay(5);
//------------------------------------------
// Get Date (UTC)
memset(data, 0, sizeof(data));
char *cDate = "";
cDate = dGPS::subStr(linea, ",", 10);
lDate = strtod(cDate, NULL);
delay(5);
//------------------------------------------
// Get Distance between current location and destination coordinates (kilometers)
float t=((desLon-fLon)*22)/1260; // difference between the longitudes in radians
float cdist=acos(cos(((90-desLat)*22)/1260)*cos(((90-fLat)*22)/1260)+sin(((90-desLat)*22)/1260)*sin(((90-fLat)*22)/1260)*cos(t)); //angular distance
fdist=6378.1*cdist; // distance= radius of earth * angular distance
//------------------------------------------
// Get Azimuth of the destination from current location
float cazimuth=asin((sin(((90-desLat)*22)/1260)*sin(t))/sin(cdist)); // temporary azimuth(in radians)
fazimuth=((cazimuth*1260)/22); // azimuth in degrees
//------------------------------------------
// Get Mode Indicator
memset(data, 0, sizeof(data));
char *cstr= subStr(linea,",",11); // Takes the whole substring at the end of the GPRMC string (eg:A*0C)
//Serial.println(cstr);
mode=subStr(cstr, "*", 1); // picks up mode indicator A from A*0C
delay(5);
//------------------------------------------
// Get Checksum value from packet and compute checksum from packet.
// used only if user entered Y or y for filtering out only valid data
memset(data, 0, sizeof(data));
checkSum = subStr(cstr, "*", 2); // picks up checksum 0C from A*0C
delay(5);
computedSum=Csum(linea); // compute checksum from the incoming string
conta=0; // Reset the buffer
memset(linea, 0, sizeof(linea));
break;
}
conta=0; // Reset the buffer
memset(linea, 0, sizeof(linea));
}
}
} // END WHILE STATEMENT
return true;
}
// Function to update Number of Satellites used, HDOP, Altitude etc.
// from the incoming $GPGGA string
boolean dGPS::updategga(){
comandoGPG[0] = '$'; // initialization
comandoGPG[1] = 'G';
comandoGPG[2] = 'P';
comandoGPG[3] = 'G';
comandoGPG[4] = 'G';
comandoGPG[5] = 'A';
while(true){
int byteGPS=-1;
byteGPS=gpsSerial.read(); //read a byte from the serial port
if (byteGPS == -1) { // See if the port is empty yet
delay(5); }
else {
linea[conta]=byteGPS; // If there is serial port data, it is put in the buffer
conta++;
if (byteGPS==13){ // If the received byte is = to 13, end of transmission
cont=0;
bien=0;
for (int i=1;i<7;i++){ // Verifies if the received command starts with $GPGGA
if (linea[i]==comandoGPG[i-1]){
bien++;
}
}
if(bien==6){ // If yes, continue and process the data
Serial.print(""); // For some reason, this needs to be here or you won't populate variables. If anyone solves this problem, let us know.
Serial.print("");
Serial.print("-");
/*Serial.println(linea); //Print out the GPGGA string (just for reference)*/
//------------------------------------------
// Get Number of satellites in use
char *data = "";
memset(data, 0, sizeof(data));
data = dGPS::subStr(linea, ",", 8);
fSat = atoi(data);
delay(5);
//------------------------------------------
// Get HDOP
memset(data, 0, sizeof(data));
data = dGPS::subStr(linea, ",", 9);
hDop = atof(data);
delay(5);
//------------------------------------------
// Get Altitude above sea-level (meters)
memset(data, 0, sizeof(data));
data = dGPS::subStr(linea, ",", 10);
fAlt = atof(data);
delay(5);
conta=0; // Reset the buffer
memset(linea, 0, sizeof(linea));
break;
}
conta=0; // Reset the buffer
memset(linea, 0, sizeof(linea));
}
}
} // END WHILE STATEMENT
return true;
}
// Function to return a substring defined by a delimiter at an index.
// Using it to parse out the GPS string.
char *dGPS::subStr (char *str, char *delim, int index) {
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;
// Since strtok consumes the first arg, make a copy
strcpy(copy, str);
for (i = 1, act = copy; i <= index; i++, act = NULL) {
//Serial.print(".");
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
}
return sub;
}
// This function converts data from GPS-style (ddmm.ssss) to decimal style (dd.mmssss)
float dGPS::conv_coords(float in_coords)
{
//Initialize the location.
float f = in_coords;
// Get the first two digits by turning f into an integer, then doing an integer divide by 100;
// firsttowdigits should be 77 at this point.
int firsttwodigits = ((int)f)/100; //This assumes that f < 10000.
float nexttwodigits = f - (float)(firsttwodigits*100);
float theFinalAnswer = (float)(firsttwodigits + nexttwodigits/60.0);
return theFinalAnswer;
}
// Calculate the checksum of the $GPRMC string received
int dGPS::Csum(char *line){
int XOR = 0;
int x;
int lenline = strlen(line);
for (int i=0;i<lenline;i++){ //Find position of '*' character in string
if(line[i]=='*') x=i;}
for (int c = 2; c < x; c++) { //start after $ till just before * and xor all the characters 1-by-1
XOR =XOR ^ (unsigned char)line[c];
}
return XOR;
}