2021 mbed Grove GPS

Dependents:   er4_2022

Committer:
c1728p9
Date:
Thu Jun 06 21:26:39 2019 -0500
Revision:
4:0ee729b4a211
Parent:
3:037ec2b52d31
Child:
5:8a5414710483
Child:
6:dffd55375288
Remove the GPS thread and dynamic memory usage

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
michaelray 0:56d6407653a7 50 double coordinate = convertGPSToDecimal(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
michaelray 0:56d6407653a7 62 double coordinate = convertGPSToDecimal(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 }
michaelray 0:56d6407653a7 69
michaelray 0:56d6407653a7 70 private:
c1728p9 4:0ee729b4a211 71 static const size_t max_line_length = 256;
c1728p9 4:0ee729b4a211 72 char _isr_line_bufs[2][max_line_length];
c1728p9 4:0ee729b4a211 73 bool _first_line_in_use;
c1728p9 4:0ee729b4a211 74 size_t _isr_line_buf_pos;
c1728p9 4:0ee729b4a211 75 char _last_line[max_line_length];
c1728p9 4:0ee729b4a211 76 bool _last_line_updated;
c1728p9 4:0ee729b4a211 77
c1728p9 4:0ee729b4a211 78 RawSerial gps_serial;
sarahmarshy 1:0607ba3aa02d 79 Mutex m;
c1728p9 4:0ee729b4a211 80
sarahmarshy 1:0607ba3aa02d 81 void read_serial() {
c1728p9 4:0ee729b4a211 82 while (gps_serial.readable()) {
c1728p9 4:0ee729b4a211 83
c1728p9 4:0ee729b4a211 84 // Check for overflow
c1728p9 4:0ee729b4a211 85 if (_isr_line_buf_pos > max_line_length -1 ) {
c1728p9 4:0ee729b4a211 86 error("GPS error - line too long");
c1728p9 4:0ee729b4a211 87 _isr_line_buf_pos = 0;
c1728p9 4:0ee729b4a211 88 }
c1728p9 4:0ee729b4a211 89
c1728p9 4:0ee729b4a211 90 // Add a character to the active buffer
c1728p9 4:0ee729b4a211 91 char *buf = _isr_line_bufs[_first_line_in_use ? 0 : 1];
c1728p9 4:0ee729b4a211 92 char value = gps_serial.getc();
c1728p9 4:0ee729b4a211 93 buf[_isr_line_buf_pos] = value;
c1728p9 4:0ee729b4a211 94 _isr_line_buf_pos++;
c1728p9 4:0ee729b4a211 95
c1728p9 4:0ee729b4a211 96 // Check for end of line
c1728p9 4:0ee729b4a211 97 if (value == '\n') {
c1728p9 4:0ee729b4a211 98 buf[_isr_line_buf_pos] = 0;
c1728p9 4:0ee729b4a211 99 _isr_line_buf_pos = 0;
c1728p9 4:0ee729b4a211 100
c1728p9 4:0ee729b4a211 101 // Save off this line if it is valid
c1728p9 4:0ee729b4a211 102 if (memcmp("$GPGGA", buf, 6) == 0) {
c1728p9 4:0ee729b4a211 103 _first_line_in_use = !_first_line_in_use;
c1728p9 4:0ee729b4a211 104 _last_line_updated = true;
c1728p9 4:0ee729b4a211 105 }
sarahmarshy 1:0607ba3aa02d 106 }
sarahmarshy 1:0607ba3aa02d 107 }
sarahmarshy 1:0607ba3aa02d 108 }
michaelray 0:56d6407653a7 109
michaelray 0:56d6407653a7 110 double convertGPSToDecimal(double coordinate) {
michaelray 0:56d6407653a7 111 int degrees = coordinate/100.0;
michaelray 0:56d6407653a7 112 int minutes = ((int)coordinate) % 100;
michaelray 0:56d6407653a7 113 double seconds = coordinate - ((int)coordinate);
michaelray 0:56d6407653a7 114 return degrees + (minutes+seconds)/60;
michaelray 0:56d6407653a7 115
michaelray 0:56d6407653a7 116 }
michaelray 0:56d6407653a7 117
michaelray 0:56d6407653a7 118 void parseLine() {
c1728p9 4:0ee729b4a211 119 bool parse_gga = false;
c1728p9 4:0ee729b4a211 120
c1728p9 4:0ee729b4a211 121 // Atomically copy the line buffer since the ISR can change it at any time
c1728p9 4:0ee729b4a211 122 core_util_critical_section_enter();
c1728p9 4:0ee729b4a211 123 if (_last_line_updated) {
c1728p9 4:0ee729b4a211 124 char *buf_saved = _isr_line_bufs[_first_line_in_use ? 1 : 0];
c1728p9 4:0ee729b4a211 125 strcpy(_last_line, buf_saved);
c1728p9 4:0ee729b4a211 126 parse_gga = true;
c1728p9 4:0ee729b4a211 127 _last_line_updated = false;
c1728p9 4:0ee729b4a211 128 }
c1728p9 4:0ee729b4a211 129 core_util_critical_section_exit();
c1728p9 4:0ee729b4a211 130
c1728p9 4:0ee729b4a211 131 if (parse_gga) {
c1728p9 4:0ee729b4a211 132 parseGGA();
c1728p9 4:0ee729b4a211 133 }
michaelray 0:56d6407653a7 134 }
michaelray 0:56d6407653a7 135
michaelray 0:56d6407653a7 136 void parseGGA() {
c1728p9 4:0ee729b4a211 137 char *line_pos = _last_line;
michaelray 0:56d6407653a7 138 for (int i=0; i<14; i++) {
michaelray 0:56d6407653a7 139 if (i==0) { // NMEA Tag
michaelray 0:56d6407653a7 140 } else if (i==1) { // UTC time
c1728p9 4:0ee729b4a211 141 gps_gga.utc_time = strtod(line_pos, 0);
michaelray 0:56d6407653a7 142 } else if (i==2) { // Latitude
c1728p9 4:0ee729b4a211 143 gps_gga.latitude = strtod(line_pos, 0);
michaelray 0:56d6407653a7 144 } else if (i==3) { // Latitude North/South indicator
c1728p9 4:0ee729b4a211 145 gps_gga.ns_indicator = line_pos[0];
michaelray 0:56d6407653a7 146 } else if (i==4) { // Longitude
c1728p9 4:0ee729b4a211 147 gps_gga.longitude = strtod(line_pos, 0);
michaelray 0:56d6407653a7 148 } else if (i==5) { // Longitude indicator
c1728p9 4:0ee729b4a211 149 gps_gga.ew_indicator = line_pos[0];
michaelray 0:56d6407653a7 150 } else if (i==6) {
c1728p9 4:0ee729b4a211 151 gps_gga.position_fix = strtod(line_pos, 0);
michaelray 0:56d6407653a7 152 }
c1728p9 4:0ee729b4a211 153 line_pos = strchr(line_pos, ',');
c1728p9 4:0ee729b4a211 154 if (line_pos == NULL) {
c1728p9 4:0ee729b4a211 155 break;
c1728p9 4:0ee729b4a211 156 }
c1728p9 4:0ee729b4a211 157 line_pos += 1;
michaelray 0:56d6407653a7 158 }
michaelray 0:56d6407653a7 159 }
michaelray 0:56d6407653a7 160 };
michaelray 0:56d6407653a7 161
sarahmarshy 1:0607ba3aa02d 162 #endif