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