-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathGPSfix.h
383 lines (313 loc) · 8.74 KB
/
GPSfix.h
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
#ifndef GPSFIX_H
#define GPSFIX_H
/**
* @file GPSfix.h
* @version 2.1
*
* @section License
* Copyright (C) 2014, SlashDevin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
// Include core libraries
#include "Cosa/Time.hh"
#include "NeoGPS_cfg.h"
#include "GPSfix_cfg.h"
/**
* A structure for holding a GPS fix: time, position, velocity, etc.
*
* Because GPS devices report various subsets of a coherent fix,
* this class tracks which members of the fix are being reported:
* each part has its own validity flag. Also, operator |= implements
* merging multiple reports into one consolidated report.
*
* @section Limitations
* Reports are not really fused with an algorithm; if present in
* the source, they are simply replaced in the destination.
*
*/
class gps_fix {
public:
gps_fix() { init(); };
/**
* A structure for holding the two parts of a floating-point number.
* This is used for Altitude, Heading and Speed, which require more
* significant digits than a 16-bit number. The decimal point is
* used as a field separator for these two parts. This is more efficient
* than calling the 32-bit math subroutines on a single scaled long integer.
* This requires knowing the exponent on the fraction when a simple type
* (e.g., float or int) is needed.
*/
struct whole_frac {
int16_t whole;
int16_t frac;
void init() { whole = 0; frac = 0; };
int32_t int32_00() const { return ((int32_t)whole) * 100L + frac; };
int16_t int16_00() const { return whole * 100 + frac; };
int32_t int32_000() const { return whole * 1000L + frac; };
float float_00() const { return ((float)whole) + ((float)frac)*0.01; };
float float_000() const { return ((float)whole) + ((float)frac)*0.001; };
} NEOGPS_PACKED;
#ifdef GPS_FIX_LOCATION
int32_t lat; // degrees * 1e7, negative is South
int32_t lon; // degrees * 1e7, negative is West
int32_t latitudeL() const { return lat; };
float latitude () const { return ((float) lat) * 1.0e-7; }; // accuracy loss
int32_t longitudeL() const { return lon; };
float longitude () const { return ((float) lon) * 1.0e-7; }; // accuracy loss
#endif
#ifdef GPS_FIX_ALTITUDE
whole_frac alt; // .01 meters
int32_t altitude_cm() const { return alt.int32_00(); };
float altitude () const { return alt.float_00(); };
#endif
#ifdef GPS_FIX_SPEED
whole_frac spd; // .001 nautical miles per hour
uint32_t speed_mkn() const { return spd.int32_000(); };
float speed () const { return spd.float_000(); };
#endif
#ifdef GPS_FIX_HEADING
whole_frac hdg; // .01 degrees
uint16_t heading_cd() const { return hdg.int16_00(); };
float heading () const { return hdg.float_00(); };
#endif
/**
* Dilution of Precision is a measure of the current satellite
* constellation geometry WRT how 'good' it is for determining a position. This
* is _independent_ of signal strength and many other factors that may be
* internal to the receiver. It _cannot_ be used to determine position accuracy
* in meters.
*/
#ifdef GPS_FIX_HDOP
uint16_t hdop; // Horizontal Dilution of Precision x 1000
#endif
#ifdef GPS_FIX_VDOP
uint16_t vdop; // Horizontal Dilution of Precision x 1000
#endif
#ifdef GPS_FIX_PDOP
uint16_t pdop; // Horizontal Dilution of Precision x 1000
#endif
#ifdef GPS_FIX_LAT_ERR
uint16_t lat_err_cm;
float lat_err() const { return lat_err_cm / 100.0; }
#endif
#ifdef GPS_FIX_LON_ERR
uint16_t lon_err_cm;
float lon_err() const { return lon_err_cm / 100.0; }
#endif
#ifdef GPS_FIX_ALT_ERR
uint16_t alt_err_cm;
float alt_err() const { return alt_err_cm / 100.0; }
#endif
#ifdef GPS_FIX_SATELLITES
uint8_t satellites;
#endif
#if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME)
time_t dateTime;
uint8_t dateTime_cs; // hundredths of a second
#endif
/**
* The current fix status or mode of the GPS device. Unfortunately, the NMEA
* sentences are a little inconsistent in their use of "status" and "mode".
* Both fields are mapped onto this enumerated type. Be aware that
* different manufacturers interpret them differently. This can cause
* problems in sentences which include both types (e.g., GPGLL).
*
* Note: Sorted by increasing accuracy. See also /operator |=/.
*/
enum status_t {
STATUS_NONE,
STATUS_EST,
STATUS_TIME_ONLY,
STATUS_STD,
STATUS_DGPS
};
status_t status NEOGPS_BF(8);
// Flags to indicate which members of this fix are valid.
struct valid_t {
bool status NEOGPS_BF(1);
#if defined(GPS_FIX_DATE)
bool date NEOGPS_BF(1);
#endif
#if defined(GPS_FIX_TIME)
bool time NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_LOCATION
bool location NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_ALTITUDE
bool altitude NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_SPEED
bool speed NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_HEADING
bool heading NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_SATELLITES
bool satellites NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_HDOP
bool hdop NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_VDOP
bool vdop NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_PDOP
bool pdop NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_LAT_ERR
bool lat_err NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_LON_ERR
bool lon_err NEOGPS_BF(1);
#endif
#ifdef GPS_FIX_ALT_ERR
bool alt_err NEOGPS_BF(1);
#endif
void init()
{
uint8_t *all = (uint8_t *) this;
for (uint8_t i=0; i<sizeof(*this); i++)
*all++ = 0;
}
void operator |=( const valid_t & r )
{
uint8_t *all = (uint8_t *) this;
const uint8_t *r_all = (const uint8_t *) &r;
for (uint8_t i=0; i<sizeof(*this); i++)
*all++ |= *r_all++;
}
} NEOGPS_PACKED
valid;
/*
* Initialize a fix. All configured members are set to zero.
*/
void init()
{
#ifdef GPS_FIX_LOCATION
lat = lon = 0;
#endif
#ifdef GPS_FIX_ALTITUDE
alt.init();
#endif
#ifdef GPS_FIX_SPEED
spd.init();
#endif
#ifdef GPS_FIX_HEADING
hdg.init();
#endif
#ifdef GPS_FIX_HDOP
hdop = 0;
#endif
#ifdef GPS_FIX_VDOP
vdop = 0;
#endif
#ifdef GPS_FIX_PDOP
pdop = 0;
#endif
#ifdef GPS_FIX_LAT_ERR
lat_err_cm = 0;
#endif
#ifdef GPS_FIX_LON_ERR
lon_err_cm = 0;
#endif
#ifdef GPS_FIX_ALT_ERR
alt_err_cm = 0;
#endif
#ifdef GPS_FIX_SATELLITES
satellites = 0;
#endif
#if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME)
dateTime = (clock_t) 0L;
#endif
#if defined(GPS_FIX_TIME)
dateTime_cs = 0;
#endif
status = STATUS_NONE;
valid.init();
};
/**
* Merge valid fields from the right fix into a "fused" fix
* on the left (i.e., /this/).
*/
gps_fix & operator |=( const gps_fix & r )
{
// Replace /status/ only if the right is more "accurate".
if (r.valid.status && (!valid.status || (status < r.status)))
status = r.status;
#ifdef GPS_FIX_DATE
if (r.valid.date) {
dateTime.date = r.dateTime.date;
dateTime.month = r.dateTime.month;
dateTime.year = r.dateTime.year;
}
#endif
#ifdef GPS_FIX_TIME
if (r.valid.time) {
dateTime.hours = r.dateTime.hours;
dateTime.minutes = r.dateTime.minutes;
dateTime.seconds = r.dateTime.seconds;
dateTime_cs = r.dateTime_cs;
}
#endif
#ifdef GPS_FIX_LOCATION
if (r.valid.location) {
lat = r.lat;
lon = r.lon;
}
#endif
#ifdef GPS_FIX_ALTITUDE
if (r.valid.altitude)
alt = r.alt;
#endif
#ifdef GPS_FIX_HEADING
if (r.valid.heading)
hdg = r.hdg;
#endif
#ifdef GPS_FIX_SPEED
if (r.valid.speed)
spd = r.spd;
#endif
#ifdef GPS_FIX_SATELLITES
if (r.valid.satellites)
satellites = r.satellites;
#endif
#ifdef GPS_FIX_HDOP
if (r.valid.hdop)
hdop = r.hdop;
#endif
#ifdef GPS_FIX_VDOP
if (r.valid.vdop)
vdop = r.vdop;
#endif
#ifdef GPS_FIX_PDOP
if (r.valid.pdop)
pdop = r.pdop;
#endif
#ifdef GPS_FIX_LAT_ERR
if (r.valid.lat_err)
lat_err_cm = r.lat_err_cm;
#endif
#ifdef GPS_FIX_LON_ERR
if (r.valid.lon_err)
lon_err_cm = r.lon_err_cm;
#endif
#ifdef GPS_FIX_ALT_ERR
if (r.valid.alt_err)
alt_err_cm = r.alt_err_cm;
#endif
// Update all the valid flags
valid |= r.valid;
return *this;
}
} NEOGPS_PACKED;
#endif