2021 mbed Grove GPS

Dependents:   er4_2022

Committer:
anthonyv
Date:
Fri Feb 12 08:18:15 2021 +0000
Revision:
6:dffd55375288
Parent:
4:0ee729b4a211
IUT mbed GPS

Who changed what in which revision?

UserRevisionLine numberNew contents of line
michaelray 0:56d6407653a7 1 #ifndef _GROVE_GPS_H_
michaelray 0:56d6407653a7 2 #define _GROVE_GPS_H_
michaelray 0:56d6407653a7 3
michaelray 0:56d6407653a7 4 #include "mbed.h"
michaelray 0:56d6407653a7 5 #include <stdlib.h>
michaelray 0:56d6407653a7 6 #include <string>
michaelray 0:56d6407653a7 7
michaelray 0:56d6407653a7 8 class GroveGPS {
michaelray 0:56d6407653a7 9
michaelray 0:56d6407653a7 10 public:
michaelray 0:56d6407653a7 11
c1728p9 4:0ee729b4a211 12 GroveGPS(PinName tx=D1, PinName rx=D0) : gps_serial(tx, rx, 9600) {
c1728p9 4:0ee729b4a211 13 memset(_isr_line_bufs, 0, sizeof(_isr_line_bufs));
c1728p9 4:0ee729b4a211 14 _first_line_in_use = true;
c1728p9 4:0ee729b4a211 15 _isr_line_buf_pos = 0;
c1728p9 4:0ee729b4a211 16 memset(_last_line, 0, sizeof(_last_line));
c1728p9 4:0ee729b4a211 17 _last_line_updated = false;
c1728p9 4:0ee729b4a211 18 gps_serial.attach(callback(this, &GroveGPS::read_serial), SerialBase::RxIrq);
michaelray 0:56d6407653a7 19 }
michaelray 0:56d6407653a7 20
michaelray 0:56d6407653a7 21 struct GGA {
michaelray 0:56d6407653a7 22 double utc_time; // Format: hhmmss.sss
michaelray 0:56d6407653a7 23 double latitude; // Format: ddmm.mmmm
michaelray 0:56d6407653a7 24 char ns_indicator; // Format: N=north or S=south
michaelray 0:56d6407653a7 25 double longitude; // Format: dddmm.mmmm
michaelray 0:56d6407653a7 26 char ew_indicator; // Format: E=east or W=west
michaelray 0:56d6407653a7 27 int position_fix; // Options: [0=not available, 1=GPS SPS mode, 2=Differential GPS, 6=dead reckoning]
michaelray 0:56d6407653a7 28 int sats_used; // Range: 0-12
michaelray 0:56d6407653a7 29 double hdop; // Horizontal Dilution of Precision
michaelray 0:56d6407653a7 30 double msl_altitude;
michaelray 0:56d6407653a7 31 char msl_altitude_units;
michaelray 0:56d6407653a7 32 double geoid_separation;
michaelray 0:56d6407653a7 33 char geoid_separation_units;
michaelray 0:56d6407653a7 34 long age_of_diff;
michaelray 0:56d6407653a7 35 long diff_ref_station_id;
michaelray 0:56d6407653a7 36 } gps_gga;
michaelray 0:56d6407653a7 37
michaelray 0:56d6407653a7 38 void getTimestamp(char* buffer) {
sarahmarshy 1:0607ba3aa02d 39 m.lock();
c1728p9 4:0ee729b4a211 40 parseLine();
c1728p9 4:0ee729b4a211 41
michaelray 0:56d6407653a7 42 sprintf(buffer, "%f", gps_gga.utc_time);
sarahmarshy 1:0607ba3aa02d 43 m.unlock();
michaelray 0:56d6407653a7 44 }
michaelray 0:56d6407653a7 45
michaelray 0:56d6407653a7 46 void getLatitude(char* buffer) {
sarahmarshy 1:0607ba3aa02d 47 m.lock();
c1728p9 4:0ee729b4a211 48 parseLine();
c1728p9 4:0ee729b4a211 49
anthonyv 6:dffd55375288 50 double coordinate = gps_gga.latitude;
michaelray 0:56d6407653a7 51 if (gps_gga.position_fix==0)
michaelray 0:56d6407653a7 52 sprintf(buffer, "N/A");
michaelray 0:56d6407653a7 53 else
michaelray 0:56d6407653a7 54 sprintf(buffer, "%c%f", (gps_gga.ns_indicator == 'N') ? '0' : '-', coordinate);
sarahmarshy 1:0607ba3aa02d 55 m.unlock();
michaelray 0:56d6407653a7 56 }
michaelray 0:56d6407653a7 57
michaelray 0:56d6407653a7 58 void getLongitude(char* buffer) {
sarahmarshy 1:0607ba3aa02d 59 m.lock();
c1728p9 4:0ee729b4a211 60 parseLine();
c1728p9 4:0ee729b4a211 61
anthonyv 6:dffd55375288 62 double coordinate = gps_gga.longitude;
michaelray 0:56d6407653a7 63 if (gps_gga.position_fix==0)
michaelray 0:56d6407653a7 64 sprintf(buffer, "N/A");
michaelray 0:56d6407653a7 65 else
michaelray 0:56d6407653a7 66 sprintf(buffer, "%c%f", (gps_gga.ew_indicator == 'E') ? '0' : '-', coordinate);
sarahmarshy 1:0607ba3aa02d 67 m.unlock();
michaelray 0:56d6407653a7 68 }
anthonyv 6:dffd55375288 69
anthonyv 6:dffd55375288 70 void getAltitude(char* buffer) {
anthonyv 6:dffd55375288 71 m.lock();
anthonyv 6:dffd55375288 72 parseLine();
anthonyv 6:dffd55375288 73
anthonyv 6:dffd55375288 74 double coordinate = gps_gga.msl_altitude;
anthonyv 6:dffd55375288 75 if (gps_gga.position_fix==0)
anthonyv 6:dffd55375288 76 sprintf(buffer, "N/A");
anthonyv 6:dffd55375288 77 else
anthonyv 6:dffd55375288 78 sprintf(buffer, " %f", coordinate);
anthonyv 6:dffd55375288 79 m.unlock();
anthonyv 6:dffd55375288 80 }
anthonyv 6:dffd55375288 81
anthonyv 6:dffd55375288 82 void update() {
anthonyv 6:dffd55375288 83 m.lock();
anthonyv 6:dffd55375288 84 parseLine();
anthonyv 6:dffd55375288 85 m.unlock();
anthonyv 6:dffd55375288 86 }
michaelray 0:56d6407653a7 87
michaelray 0:56d6407653a7 88 private:
c1728p9 4:0ee729b4a211 89 static const size_t max_line_length = 256;
c1728p9 4:0ee729b4a211 90 char _isr_line_bufs[2][max_line_length];
c1728p9 4:0ee729b4a211 91 bool _first_line_in_use;
c1728p9 4:0ee729b4a211 92 size_t _isr_line_buf_pos;
c1728p9 4:0ee729b4a211 93 char _last_line[max_line_length];
c1728p9 4:0ee729b4a211 94 bool _last_line_updated;
c1728p9 4:0ee729b4a211 95
c1728p9 4:0ee729b4a211 96 RawSerial gps_serial;
sarahmarshy 1:0607ba3aa02d 97 Mutex m;
c1728p9 4:0ee729b4a211 98
sarahmarshy 1:0607ba3aa02d 99 void read_serial() {
c1728p9 4:0ee729b4a211 100 while (gps_serial.readable()) {
c1728p9 4:0ee729b4a211 101
c1728p9 4:0ee729b4a211 102 // Check for overflow
c1728p9 4:0ee729b4a211 103 if (_isr_line_buf_pos > max_line_length -1 ) {
c1728p9 4:0ee729b4a211 104 error("GPS error - line too long");
c1728p9 4:0ee729b4a211 105 _isr_line_buf_pos = 0;
c1728p9 4:0ee729b4a211 106 }
c1728p9 4:0ee729b4a211 107
c1728p9 4:0ee729b4a211 108 // Add a character to the active buffer
c1728p9 4:0ee729b4a211 109 char *buf = _isr_line_bufs[_first_line_in_use ? 0 : 1];
c1728p9 4:0ee729b4a211 110 char value = gps_serial.getc();
c1728p9 4:0ee729b4a211 111 buf[_isr_line_buf_pos] = value;
c1728p9 4:0ee729b4a211 112 _isr_line_buf_pos++;
c1728p9 4:0ee729b4a211 113
c1728p9 4:0ee729b4a211 114 // Check for end of line
c1728p9 4:0ee729b4a211 115 if (value == '\n') {
c1728p9 4:0ee729b4a211 116 buf[_isr_line_buf_pos] = 0;
c1728p9 4:0ee729b4a211 117 _isr_line_buf_pos = 0;
c1728p9 4:0ee729b4a211 118
c1728p9 4:0ee729b4a211 119 // Save off this line if it is valid
c1728p9 4:0ee729b4a211 120 if (memcmp("$GPGGA", buf, 6) == 0) {
c1728p9 4:0ee729b4a211 121 _first_line_in_use = !_first_line_in_use;
c1728p9 4:0ee729b4a211 122 _last_line_updated = true;
c1728p9 4:0ee729b4a211 123 }
sarahmarshy 1:0607ba3aa02d 124 }
sarahmarshy 1:0607ba3aa02d 125 }
sarahmarshy 1:0607ba3aa02d 126 }
michaelray 0:56d6407653a7 127
michaelray 0:56d6407653a7 128 double convertGPSToDecimal(double coordinate) {
michaelray 0:56d6407653a7 129 int degrees = coordinate/100.0;
michaelray 0:56d6407653a7 130 int minutes = ((int)coordinate) % 100;
michaelray 0:56d6407653a7 131 double seconds = coordinate - ((int)coordinate);
michaelray 0:56d6407653a7 132 return degrees + (minutes+seconds)/60;
michaelray 0:56d6407653a7 133
michaelray 0:56d6407653a7 134 }
michaelray 0:56d6407653a7 135
michaelray 0:56d6407653a7 136 void parseLine() {
c1728p9 4:0ee729b4a211 137 bool parse_gga = false;
c1728p9 4:0ee729b4a211 138
c1728p9 4:0ee729b4a211 139 // Atomically copy the line buffer since the ISR can change it at any time
c1728p9 4:0ee729b4a211 140 core_util_critical_section_enter();
c1728p9 4:0ee729b4a211 141 if (_last_line_updated) {
c1728p9 4:0ee729b4a211 142 char *buf_saved = _isr_line_bufs[_first_line_in_use ? 1 : 0];
c1728p9 4:0ee729b4a211 143 strcpy(_last_line, buf_saved);
c1728p9 4:0ee729b4a211 144 parse_gga = true;
c1728p9 4:0ee729b4a211 145 _last_line_updated = false;
c1728p9 4:0ee729b4a211 146 }
c1728p9 4:0ee729b4a211 147 core_util_critical_section_exit();
c1728p9 4:0ee729b4a211 148
c1728p9 4:0ee729b4a211 149 if (parse_gga) {
c1728p9 4:0ee729b4a211 150 parseGGA();
c1728p9 4:0ee729b4a211 151 }
michaelray 0:56d6407653a7 152 }
michaelray 0:56d6407653a7 153
michaelray 0:56d6407653a7 154 void parseGGA() {
c1728p9 4:0ee729b4a211 155 char *line_pos = _last_line;
michaelray 0:56d6407653a7 156 for (int i=0; i<14; i++) {
michaelray 0:56d6407653a7 157 if (i==0) { // NMEA Tag
michaelray 0:56d6407653a7 158 } else if (i==1) { // UTC time
c1728p9 4:0ee729b4a211 159 gps_gga.utc_time = strtod(line_pos, 0);
anthonyv 6:dffd55375288 160
anthonyv 6:dffd55375288 161
michaelray 0:56d6407653a7 162 } else if (i==2) { // Latitude
c1728p9 4:0ee729b4a211 163 gps_gga.latitude = strtod(line_pos, 0);
anthonyv 6:dffd55375288 164 gps_gga.latitude=convertGPSToDecimal(gps_gga.latitude);
anthonyv 6:dffd55375288 165
michaelray 0:56d6407653a7 166 } else if (i==3) { // Latitude North/South indicator
c1728p9 4:0ee729b4a211 167 gps_gga.ns_indicator = line_pos[0];
michaelray 0:56d6407653a7 168 } else if (i==4) { // Longitude
c1728p9 4:0ee729b4a211 169 gps_gga.longitude = strtod(line_pos, 0);
anthonyv 6:dffd55375288 170 gps_gga.longitude=convertGPSToDecimal(gps_gga.longitude);
michaelray 0:56d6407653a7 171 } else if (i==5) { // Longitude indicator
c1728p9 4:0ee729b4a211 172 gps_gga.ew_indicator = line_pos[0];
michaelray 0:56d6407653a7 173 } else if (i==6) {
anthonyv 6:dffd55375288 174 gps_gga.position_fix= strtod(line_pos, 0);
anthonyv 6:dffd55375288 175 }
anthonyv 6:dffd55375288 176 else if (i==7) {
anthonyv 6:dffd55375288 177 gps_gga.sats_used= strtod(line_pos, 0);//nb satellite used
michaelray 0:56d6407653a7 178 }
anthonyv 6:dffd55375288 179 else if (i==8) {
anthonyv 6:dffd55375288 180 gps_gga.hdop= strtod(line_pos, 0);//horizontal precision
anthonyv 6:dffd55375288 181 }
anthonyv 6:dffd55375288 182 else if (i==9) {
anthonyv 6:dffd55375288 183 gps_gga.msl_altitude= strtod(line_pos, 0);//altitute
anthonyv 6:dffd55375288 184 }
anthonyv 6:dffd55375288 185
anthonyv 6:dffd55375288 186
c1728p9 4:0ee729b4a211 187 line_pos = strchr(line_pos, ',');
c1728p9 4:0ee729b4a211 188 if (line_pos == NULL) {
c1728p9 4:0ee729b4a211 189 break;
c1728p9 4:0ee729b4a211 190 }
c1728p9 4:0ee729b4a211 191 line_pos += 1;
michaelray 0:56d6407653a7 192 }
michaelray 0:56d6407653a7 193 }
michaelray 0:56d6407653a7 194 };
michaelray 0:56d6407653a7 195
sarahmarshy 1:0607ba3aa02d 196 #endif