2021 mbed Grove GPS

Dependents:   er4_2022

Committer:
c1728p9
Date:
Thu Jun 06 20:17:47 2019 -0500
Revision:
3:037ec2b52d31
Parent:
2:82fce70de15f
Child:
4:0ee729b4a211
Prevent memory allocation failures by limiting line length

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
sarahmarshy 2:82fce70de15f 12 GroveGPS(PinName tx=D1, PinName rx=D0) : _last_line(""), gps_serial(tx, rx, 9600) {}
michaelray 0:56d6407653a7 13
michaelray 0:56d6407653a7 14 void readCharacter(char newCharacter) {
michaelray 0:56d6407653a7 15 if (newCharacter == '\n') {
michaelray 0:56d6407653a7 16 parseLine();
michaelray 0:56d6407653a7 17 _last_line = "";
michaelray 0:56d6407653a7 18 } else {
michaelray 0:56d6407653a7 19 _last_line += newCharacter;
michaelray 0:56d6407653a7 20 }
c1728p9 3:037ec2b52d31 21
c1728p9 3:037ec2b52d31 22 if (_last_line.length() > max_line_length) {
c1728p9 3:037ec2b52d31 23 error("GPS error - line too long");
c1728p9 3:037ec2b52d31 24 _last_line = "";
c1728p9 3:037ec2b52d31 25 }
michaelray 0:56d6407653a7 26 }
michaelray 0:56d6407653a7 27
michaelray 0:56d6407653a7 28 struct GGA {
michaelray 0:56d6407653a7 29 double utc_time; // Format: hhmmss.sss
michaelray 0:56d6407653a7 30 double latitude; // Format: ddmm.mmmm
michaelray 0:56d6407653a7 31 char ns_indicator; // Format: N=north or S=south
michaelray 0:56d6407653a7 32 double longitude; // Format: dddmm.mmmm
michaelray 0:56d6407653a7 33 char ew_indicator; // Format: E=east or W=west
michaelray 0:56d6407653a7 34 int position_fix; // Options: [0=not available, 1=GPS SPS mode, 2=Differential GPS, 6=dead reckoning]
michaelray 0:56d6407653a7 35 int sats_used; // Range: 0-12
michaelray 0:56d6407653a7 36 double hdop; // Horizontal Dilution of Precision
michaelray 0:56d6407653a7 37 double msl_altitude;
michaelray 0:56d6407653a7 38 char msl_altitude_units;
michaelray 0:56d6407653a7 39 double geoid_separation;
michaelray 0:56d6407653a7 40 char geoid_separation_units;
michaelray 0:56d6407653a7 41 long age_of_diff;
michaelray 0:56d6407653a7 42 long diff_ref_station_id;
michaelray 0:56d6407653a7 43 std::string checksum;
michaelray 0:56d6407653a7 44 } gps_gga;
michaelray 0:56d6407653a7 45
michaelray 0:56d6407653a7 46 void getTimestamp(char* buffer) {
sarahmarshy 1:0607ba3aa02d 47 m.lock();
michaelray 0:56d6407653a7 48 sprintf(buffer, "%f", gps_gga.utc_time);
sarahmarshy 1:0607ba3aa02d 49 m.unlock();
michaelray 0:56d6407653a7 50 }
michaelray 0:56d6407653a7 51
michaelray 0:56d6407653a7 52 void getLatitude(char* buffer) {
sarahmarshy 1:0607ba3aa02d 53 m.lock();
michaelray 0:56d6407653a7 54 double coordinate = convertGPSToDecimal(gps_gga.latitude);
michaelray 0:56d6407653a7 55 if (gps_gga.position_fix==0)
michaelray 0:56d6407653a7 56 sprintf(buffer, "N/A");
michaelray 0:56d6407653a7 57 else
michaelray 0:56d6407653a7 58 sprintf(buffer, "%c%f", (gps_gga.ns_indicator == 'N') ? '0' : '-', coordinate);
sarahmarshy 1:0607ba3aa02d 59 m.unlock();
michaelray 0:56d6407653a7 60 }
michaelray 0:56d6407653a7 61
michaelray 0:56d6407653a7 62 void getLongitude(char* buffer) {
sarahmarshy 1:0607ba3aa02d 63 m.lock();
michaelray 0:56d6407653a7 64 double coordinate = convertGPSToDecimal(gps_gga.longitude);
michaelray 0:56d6407653a7 65 if (gps_gga.position_fix==0)
michaelray 0:56d6407653a7 66 sprintf(buffer, "N/A");
michaelray 0:56d6407653a7 67 else
michaelray 0:56d6407653a7 68 sprintf(buffer, "%c%f", (gps_gga.ew_indicator == 'E') ? '0' : '-', coordinate);
sarahmarshy 1:0607ba3aa02d 69 m.unlock();
michaelray 0:56d6407653a7 70 }
sarahmarshy 1:0607ba3aa02d 71
sarahmarshy 1:0607ba3aa02d 72 void start() {
sarahmarshy 1:0607ba3aa02d 73 serial_thread.start(callback(this, &GroveGPS::read_serial));
sarahmarshy 1:0607ba3aa02d 74 }
sarahmarshy 1:0607ba3aa02d 75
michaelray 0:56d6407653a7 76
michaelray 0:56d6407653a7 77 private:
c1728p9 3:037ec2b52d31 78 static const size_t max_line_length = 1024;
michaelray 0:56d6407653a7 79 std::string _last_line;
sarahmarshy 1:0607ba3aa02d 80 Thread serial_thread;
sarahmarshy 1:0607ba3aa02d 81 Serial gps_serial;
sarahmarshy 1:0607ba3aa02d 82 Mutex m;
sarahmarshy 1:0607ba3aa02d 83 void read_serial() {
sarahmarshy 1:0607ba3aa02d 84 while (true) {
sarahmarshy 1:0607ba3aa02d 85 if (gps_serial.readable()) {
sarahmarshy 1:0607ba3aa02d 86 readCharacter(gps_serial.getc());
sarahmarshy 1:0607ba3aa02d 87 }
sarahmarshy 1:0607ba3aa02d 88 }
sarahmarshy 1:0607ba3aa02d 89 }
michaelray 0:56d6407653a7 90
michaelray 0:56d6407653a7 91 double convertGPSToDecimal(double coordinate) {
michaelray 0:56d6407653a7 92 int degrees = coordinate/100.0;
michaelray 0:56d6407653a7 93 int minutes = ((int)coordinate) % 100;
michaelray 0:56d6407653a7 94 double seconds = coordinate - ((int)coordinate);
michaelray 0:56d6407653a7 95 return degrees + (minutes+seconds)/60;
michaelray 0:56d6407653a7 96
michaelray 0:56d6407653a7 97 }
michaelray 0:56d6407653a7 98
michaelray 0:56d6407653a7 99 void parseLine() {
michaelray 0:56d6407653a7 100 if (_last_line.find("GPGGA") != std::string::npos) {
sarahmarshy 1:0607ba3aa02d 101 m.lock();
michaelray 0:56d6407653a7 102 parseGGA();
sarahmarshy 1:0607ba3aa02d 103 m.unlock();
michaelray 0:56d6407653a7 104 }
michaelray 0:56d6407653a7 105 }
michaelray 0:56d6407653a7 106
michaelray 0:56d6407653a7 107 void parseGGA() {
michaelray 0:56d6407653a7 108 char* pEnd;
michaelray 0:56d6407653a7 109 for (int i=0; i<14; i++) {
michaelray 0:56d6407653a7 110 std::string current_item = _last_line.substr(0,_last_line.find(","));
michaelray 0:56d6407653a7 111 _last_line = _last_line.substr(_last_line.find(",")+1);
michaelray 0:56d6407653a7 112 if (i==0) { // NMEA Tag
michaelray 0:56d6407653a7 113 } else if (i==1) { // UTC time
michaelray 0:56d6407653a7 114 gps_gga.utc_time = strtod(current_item.c_str(), &pEnd);
michaelray 0:56d6407653a7 115 } else if (i==2) { // Latitude
michaelray 0:56d6407653a7 116 gps_gga.latitude = strtod(current_item.c_str(), &pEnd);
michaelray 0:56d6407653a7 117 } else if (i==3) { // Latitude North/South indicator
michaelray 0:56d6407653a7 118 gps_gga.ns_indicator = current_item[0];
michaelray 0:56d6407653a7 119 } else if (i==4) { // Longitude
michaelray 0:56d6407653a7 120 gps_gga.longitude = strtod(current_item.c_str(), &pEnd);
michaelray 0:56d6407653a7 121 } else if (i==5) { // Longitude indicator
michaelray 0:56d6407653a7 122 gps_gga.ew_indicator = current_item[0];
michaelray 0:56d6407653a7 123 } else if (i==6) {
michaelray 0:56d6407653a7 124 gps_gga.position_fix = strtod(current_item.c_str(), &pEnd);
michaelray 0:56d6407653a7 125 }
michaelray 0:56d6407653a7 126 }
michaelray 0:56d6407653a7 127 }
michaelray 0:56d6407653a7 128 };
michaelray 0:56d6407653a7 129
sarahmarshy 1:0607ba3aa02d 130 #endif