Louis Boisaubert / ProjetInterfacage

Dependencies:   BSP_DISCO_F746NG

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GroveGPS.h Source File

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