Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BSP_DISCO_F746NG
GroveGPS.h
00001 #ifndef _GROVE_GPS_H_ 00002 #define _GROVE_GPS_H_ 00003 00004 #include "mbed.h" 00005 #include <stdlib.h> 00006 #include <string> 00007 00008 class GroveGPS { 00009 00010 public: 00011 00012 GroveGPS(PinName tx=D1, PinName rx=D0) : gps_serial(tx, rx, 9600) { 00013 memset(_isr_line_bufs, 0, sizeof(_isr_line_bufs)); 00014 _first_line_in_use = true; 00015 _isr_line_buf_pos = 0; 00016 memset(_last_line, 0, sizeof(_last_line)); 00017 _last_line_updated = false; 00018 gps_serial.attach(callback(this, &GroveGPS::read_serial), SerialBase::RxIrq); 00019 } 00020 00021 struct GGA { 00022 double utc_time; // Format: hhmmss.sss 00023 double latitude; // Format: ddmm.mmmm 00024 char ns_indicator; // Format: N=north or S=south 00025 double longitude; // Format: dddmm.mmmm 00026 char ew_indicator; // Format: E=east or W=west 00027 int position_fix; // Options: [0=not available, 1=GPS SPS mode, 2=Differential GPS, 6=dead reckoning] 00028 int sats_used; // Range: 0-12 00029 double hdop; // Horizontal Dilution of Precision 00030 double msl_altitude; 00031 char msl_altitude_units; 00032 double geoid_separation; 00033 char geoid_separation_units; 00034 long age_of_diff; 00035 long diff_ref_station_id; 00036 } gps_gga; 00037 00038 bool getTimestamp(char* buffer) { 00039 m.lock(); 00040 parseLine(); 00041 00042 bool valid = gps_gga.position_fix != 0; 00043 sprintf(buffer, "%d", (int)(gps_gga.utc_time)); 00044 m.unlock(); 00045 00046 return valid; 00047 } 00048 00049 bool getLatitude(char* buffer) { 00050 m.lock(); 00051 parseLine(); 00052 00053 bool valid = false; 00054 double coordinate = convertGPSToDecimal(gps_gga.latitude); 00055 if (gps_gga.position_fix==0) { 00056 sprintf(buffer, "N/A"); 00057 } else { 00058 sprintf(buffer, "%c%f", (gps_gga.ns_indicator == 'N') ? '0' : '-', coordinate); 00059 valid = true; 00060 } 00061 m.unlock(); 00062 00063 return valid; 00064 } 00065 00066 bool getLongitude(char* buffer) { 00067 m.lock(); 00068 parseLine(); 00069 00070 bool valid = false; 00071 double coordinate = convertGPSToDecimal(gps_gga.longitude); 00072 if (gps_gga.position_fix==0) { 00073 sprintf(buffer, "N/A"); 00074 } else { 00075 sprintf(buffer, "%c%f", (gps_gga.ew_indicator == 'E') ? '0' : '-', coordinate); 00076 valid = true; 00077 } 00078 m.unlock(); 00079 00080 return valid; 00081 } 00082 00083 private: 00084 static const size_t max_line_length = 256; 00085 char _isr_line_bufs[2][max_line_length]; 00086 bool _first_line_in_use; 00087 size_t _isr_line_buf_pos; 00088 char _last_line[max_line_length]; 00089 bool _last_line_updated; 00090 00091 UnbufferedSerial gps_serial; 00092 Mutex m; 00093 00094 void read_serial() { 00095 while (gps_serial.readable()) { 00096 00097 // Check for overflow 00098 if (_isr_line_buf_pos > max_line_length -1 ) { 00099 error("GPS error - line too long"); 00100 _isr_line_buf_pos = 0; 00101 } 00102 00103 // Add a character to the active buffer 00104 char *buf = _isr_line_bufs[_first_line_in_use ? 0 : 1]; 00105 char value; 00106 gps_serial.read(&value, 1); 00107 buf[_isr_line_buf_pos] = value; 00108 _isr_line_buf_pos++; 00109 00110 // Check for end of line 00111 if (value == '\n') { 00112 buf[_isr_line_buf_pos] = 0; 00113 _isr_line_buf_pos = 0; 00114 00115 // Save off this line if it is valid 00116 if (memcmp("$GPGGA", buf, 6) == 0) { 00117 _first_line_in_use = !_first_line_in_use; 00118 _last_line_updated = true; 00119 } 00120 } 00121 } 00122 } 00123 00124 double convertGPSToDecimal(double coordinate) { 00125 int degrees = coordinate/100.0; 00126 int minutes = ((int)coordinate) % 100; 00127 double seconds = coordinate - ((int)coordinate); 00128 return degrees + (minutes+seconds)/60; 00129 00130 } 00131 00132 void parseLine() { 00133 bool parse_gga = false; 00134 00135 // Atomically copy the line buffer since the ISR can change it at any time 00136 core_util_critical_section_enter(); 00137 if (_last_line_updated) { 00138 char *buf_saved = _isr_line_bufs[_first_line_in_use ? 1 : 0]; 00139 strcpy(_last_line, buf_saved); 00140 parse_gga = true; 00141 _last_line_updated = false; 00142 } 00143 core_util_critical_section_exit(); 00144 00145 if (parse_gga) { 00146 parseGGA(); 00147 } 00148 } 00149 00150 void parseGGA() { 00151 char *line_pos = _last_line; 00152 for (int i=0; i<14; i++) { 00153 if (i==0) { // NMEA Tag 00154 } else if (i==1) { // UTC time 00155 gps_gga.utc_time = strtod(line_pos, 0); 00156 } else if (i==2) { // Latitude 00157 gps_gga.latitude = strtod(line_pos, 0); 00158 } else if (i==3) { // Latitude North/South indicator 00159 gps_gga.ns_indicator = line_pos[0]; 00160 } else if (i==4) { // Longitude 00161 gps_gga.longitude = strtod(line_pos, 0); 00162 } else if (i==5) { // Longitude indicator 00163 gps_gga.ew_indicator = line_pos[0]; 00164 } else if (i==6) { 00165 gps_gga.position_fix = strtod(line_pos, 0); 00166 } 00167 line_pos = strchr(line_pos, ','); 00168 if (line_pos == NULL) { 00169 break; 00170 } 00171 line_pos += 1; 00172 } 00173 } 00174 }; 00175 00176 #endif
Generated on Tue Jul 26 2022 15:43:48 by
1.7.2